From 20fc378cae03f792fe200760fd66f00452c00735 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 29 Mar 2018 09:56:58 -0400 Subject: [PATCH 01/31] Adding log messages to help debug this --- src/GitHub.Api/Platform/ProcessEnvironment.cs | 4 ++++ .../Assets/Editor/GitHub.Unity/UI/GitPathView.cs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/GitHub.Api/Platform/ProcessEnvironment.cs b/src/GitHub.Api/Platform/ProcessEnvironment.cs index adc606e9b..941bc57b4 100644 --- a/src/GitHub.Api/Platform/ProcessEnvironment.cs +++ b/src/GitHub.Api/Platform/ProcessEnvironment.cs @@ -25,6 +25,7 @@ public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSet if (!Environment.GitInstallPath.IsInitialized || dontSetupGit) return; + Logger.Trace("Environment.GitExecutablePath", Environment.GitExecutablePath); Guard.ArgumentNotNull(psi, "psi"); @@ -67,6 +68,9 @@ public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSet path = $"{gitExecutableDir}:{binPath}:{execPath}:{gitLfsPath}:{Environment.Path}:{developerPaths}"; } + Logger.Trace("Environment Path: {0}", Environment.Path); + Logger.Trace("Calculated Path: {0}", path); + if (execPath.IsInitialized) psi.EnvironmentVariables["GIT_EXEC_PATH"] = execPath.ToString(); diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs index 2366f7249..20da28137 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs @@ -213,7 +213,7 @@ private void CheckEnteredGitPath() private void ValidateAndSetGitInstallPath(string value) { - //Logger.Trace("Validating Git Path:{0}", value); + Logger.Trace("Validating Git Path:{0}", value); gitVersionErrorMessage = null; From 951780b16dfb2a5837841d06c928a2eb23d760e7 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 29 Mar 2018 10:05:46 -0400 Subject: [PATCH 02/31] Fixing log message --- src/GitHub.Api/Platform/ProcessEnvironment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitHub.Api/Platform/ProcessEnvironment.cs b/src/GitHub.Api/Platform/ProcessEnvironment.cs index 941bc57b4..1a5890335 100644 --- a/src/GitHub.Api/Platform/ProcessEnvironment.cs +++ b/src/GitHub.Api/Platform/ProcessEnvironment.cs @@ -25,7 +25,7 @@ public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSet if (!Environment.GitInstallPath.IsInitialized || dontSetupGit) return; - Logger.Trace("Environment.GitExecutablePath", Environment.GitExecutablePath); + Logger.Trace("Environment.GitExecutablePath: {0}", Environment.GitExecutablePath); Guard.ArgumentNotNull(psi, "psi"); From e49517fb63d4bb97a962e6cdf49f68daeb2a166d Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 29 Mar 2018 10:22:17 -0400 Subject: [PATCH 03/31] Moving log message --- src/GitHub.Api/Platform/ProcessEnvironment.cs | 3 ++- vim.exe.stackdump | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 vim.exe.stackdump diff --git a/src/GitHub.Api/Platform/ProcessEnvironment.cs b/src/GitHub.Api/Platform/ProcessEnvironment.cs index 1a5890335..aaff796a4 100644 --- a/src/GitHub.Api/Platform/ProcessEnvironment.cs +++ b/src/GitHub.Api/Platform/ProcessEnvironment.cs @@ -25,7 +25,6 @@ public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSet if (!Environment.GitInstallPath.IsInitialized || dontSetupGit) return; - Logger.Trace("Environment.GitExecutablePath: {0}", Environment.GitExecutablePath); Guard.ArgumentNotNull(psi, "psi"); @@ -35,6 +34,8 @@ public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSet var gitLfsPath = Environment.GitInstallPath; var gitExecutableDir = Environment.GitExecutablePath.Parent; // original path to git (might be different from install path if it's a symlink) + Logger.Trace("Environment.GitExecutablePath: {0}", Environment.GitExecutablePath); + // Paths to developer tools such as msbuild.exe //var developerPaths = StringExtensions.JoinForAppending(";", developerEnvironment.GetPaths()); var developerPaths = ""; diff --git a/vim.exe.stackdump b/vim.exe.stackdump new file mode 100644 index 000000000..8099f8995 --- /dev/null +++ b/vim.exe.stackdump @@ -0,0 +1,19 @@ +Stack trace: +Frame Function Args +00180238000 0018005D19E (00180223639, 00180223C39, 001802342F0, 000FFFFB690) +00180238000 001800463F9 (C0C0C000008080, FF000000808080, FFFF000000FF00, FF00FF000000FF) +00180238000 00180046432 (00180223616, 000000001E7, 001802342F0, 80808000C0C0C0) +00180238000 001800431E3 (00000000000, 00180238000, 7FF92F90D6DE, 001800004EC) +00180238000 0018006B101 (C0C0C000008080, FF000000808080, FFFF000000FF00, FF00FF000000FF) +00180238000 0018006BF4C (00000000000, 0010065D548, 00000000000, 00000000000) +00180238000 0018006E066 (00000000000, 00000000008, 005FCB3E280, 00000000000) +00000000001 00180135376 (0010065D540, 00000000008, 00000000000, 00000000000) +00000000001 0018011C6FB (0010065D540, 00000000008, 00000000000, 00000000000) +00000000001 001004F77E4 (00100575E0A, 00100663D08, 00000000000, 00100663D0C) +00000000001 001005820F3 (00000000008, 00100664140, 00000000000, 00000000000) +00000000001 00100576D86 (000241E9F28, 0005A6893D4, 000241E9F28, 00000010000) +00000000001 001005D4CEB (00000000000, 00000000000, 0000000000B, 000FFFFCBD0) +0060004F000 001005E218A (00000000043, 000FFFFCC54, 00000000030, 30001000000FF00) +000FFFFCCB0 001800479F7 (00000000000, 00000000000, 00000000000, 00000000000) +00000000000 00180045663 (00000000000, 00000000000, 00000000000, 00000000000) +End of stack trace (more stack frames may be present) From 700500bb37834a207876203da6877cac23505cc0 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 29 Mar 2018 12:47:28 -0400 Subject: [PATCH 04/31] Adding functionality to change to the internal portable git if available --- .../Editor/GitHub.Unity/UI/GitPathView.cs | 146 ++++++++++++------ 1 file changed, 99 insertions(+), 47 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs index 17128c4ac..e3c4f6846 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs @@ -11,10 +11,12 @@ class GitPathView : Subview private const string GitInstallTitle = "Git installation"; private const string PathToGit = "Path to Git"; private const string GitPathSaveButton = "Save Path"; - private const string GitInstallFindButton = "Find install"; + private const string UseInternalGitButton = "Use internal git"; + private const string FindSystemGitButton = "Find system git"; private const string BrowseButton = "..."; private const string GitInstallBrowseTitle = "Select git binary"; private const string ErrorInvalidPathMessage = "Invalid Path."; + private const string ErrorInstallingInternalGit = "Error installing portable git."; private const string ErrorValidatingGitPath = "Error validating Git Path."; private const string ErrorGitNotFoundMessage = "Git not found."; private const string ErrorGitLfsNotFoundMessage = "Git LFS not found."; @@ -33,11 +35,15 @@ class GitPathView : Subview [NonSerialized] private bool isBusy; [NonSerialized] private bool gitExecHasChanged; [NonSerialized] private bool gitExecutableIsSet; + [NonSerialized] private string portableGitPath; public override void InitializeView(IView parent) { base.InitializeView(parent); gitExecutableIsSet = Environment.GitExecutablePath.IsInitialized; + + var gitInstallDetails = new GitInstaller.GitInstallDetails(Environment.UserCachePath, Environment.IsWindows); + portableGitPath = gitInstallDetails.GitExecutablePath; } public override void OnEnable() @@ -112,8 +118,21 @@ public override void OnGUI() } EditorGUI.EndDisabledGroup(); + // disable if we are not on windows + // disable if the newPath == portableGitPath + EditorGUI.BeginDisabledGroup(!Environment.IsWindows || Environment.IsWindows && newGitExec == portableGitPath); + if (GUILayout.Button(UseInternalGitButton, GUILayout.ExpandWidth(false))) + { + GUI.FocusControl(null); + + Logger.Trace("Expected portableGitPath: {0}", portableGitPath); + newGitExec = portableGitPath; + CheckEnteredGitPath(); + } + EditorGUI.EndDisabledGroup(); + //Find button - for attempting to locate a new install - if (GUILayout.Button(GitInstallFindButton, GUILayout.ExpandWidth(false))) + if (GUILayout.Button(FindSystemGitButton, GUILayout.ExpandWidth(false))) { GUI.FocusControl(null); isBusy = true; @@ -213,72 +232,105 @@ private void CheckEnteredGitPath() private void ValidateAndSetGitInstallPath(string value) { - //Logger.Trace("Validating Git Path:{0}", value); + value = value.Trim(); - gitVersionErrorMessage = null; + if (value == portableGitPath) + { + Logger.Trace("Attempting to restore portable Git Path:{0}", value); - GitClient.ValidateGitInstall(value.ToNPath()) - .FinallyInUI((success, exception, result) => - { - if (!success) - { - Logger.Trace(ErrorValidatingGitPath); - gitVersionErrorMessage = ErrorValidatingGitPath; - } - else if (!result.IsValid) - { - Logger.Warning( - "Software versions do not meet minimums Git:{0} (Minimum:{1}) GitLfs:{2} (Minimum:{3})", - result.GitVersion, Constants.MinimumGitVersion, result.GitLfsVersion, - Constants.MinimumGitLfsVersion); + var gitInstaller = new GitInstaller(Environment, EntryPoint.ApplicationManager.ProcessManager, + EntryPoint.ApplicationManager.TaskManager); - var errorMessageStringBuilder = new StringBuilder(); + gitInstaller.SetupGitIfNeeded() + .FinallyInUI((success, exception, result) => + { + Logger.Trace("Setup Git Using the installer:{0}", success); - if (result.GitVersion == null) + if (!success) { - errorMessageStringBuilder.Append(ErrorGitNotFoundMessage); + Logger.Error(exception, ErrorInstallingInternalGit); + gitVersionErrorMessage = ErrorValidatingGitPath; } - else if (result.GitLfsVersion == null) + else { - errorMessageStringBuilder.Append(ErrorGitLfsNotFoundMessage); + Manager.SystemSettings.Unset(Constants.GitInstallPathKey); + Environment.GitExecutablePath = result; + + gitExecHasChanged = true; } - else + + isBusy = false; + }).Start(); + } + else + { + //Logger.Trace("Validating Git Path:{0}", value); + + gitVersionErrorMessage = null; + + GitClient.ValidateGitInstall(value.ToNPath()) + .FinallyInUI((success, exception, result) => + { + if (!success) + { + Logger.Trace(ErrorValidatingGitPath); + gitVersionErrorMessage = ErrorValidatingGitPath; + } + else if (!result.IsValid) { - if (result.GitVersion < Constants.MinimumGitVersion) + Logger.Warning( + "Software versions do not meet minimums Git:{0} (Minimum:{1}) GitLfs:{2} (Minimum:{3})", + result.GitVersion, Constants.MinimumGitVersion, result.GitLfsVersion, + Constants.MinimumGitLfsVersion); + + var errorMessageStringBuilder = new StringBuilder(); + + if (result.GitVersion == null) { - errorMessageStringBuilder.AppendFormat(ErrorMinimumGitVersionMessageFormat, - result.GitVersion, Constants.MinimumGitVersion); + errorMessageStringBuilder.Append(ErrorGitNotFoundMessage); } - - if (result.GitLfsVersion < Constants.MinimumGitLfsVersion) + else if (result.GitLfsVersion == null) { - if (errorMessageStringBuilder.Length > 0) + errorMessageStringBuilder.Append(ErrorGitLfsNotFoundMessage); + } + else + { + if (result.GitVersion < Constants.MinimumGitVersion) { - errorMessageStringBuilder.Append(Environment.NewLine); + errorMessageStringBuilder.AppendFormat(ErrorMinimumGitVersionMessageFormat, + result.GitVersion, Constants.MinimumGitVersion); } - errorMessageStringBuilder.AppendFormat(ErrorMinimumGitLfsVersionMessageFormat, - result.GitLfsVersion, Constants.MinimumGitLfsVersion); + if (result.GitLfsVersion < Constants.MinimumGitLfsVersion) + { + if (errorMessageStringBuilder.Length > 0) + { + errorMessageStringBuilder.Append(Environment.NewLine); + } + + errorMessageStringBuilder.AppendFormat(ErrorMinimumGitLfsVersionMessageFormat, + result.GitLfsVersion, Constants.MinimumGitLfsVersion); + } } - } - gitVersionErrorMessage = errorMessageStringBuilder.ToString(); - } - else - { - Logger.Trace("Software versions meet minimums Git:{0} GitLfs:{1}", - result.GitVersion, - result.GitLfsVersion); + gitVersionErrorMessage = errorMessageStringBuilder.ToString(); + } + else + { + Logger.Trace("Software versions meet minimums Git:{0} GitLfs:{1}", + result.GitVersion, + result.GitLfsVersion); - Manager.SystemSettings.Set(Constants.GitInstallPathKey, value); - Environment.GitExecutablePath = value.ToNPath(); + Manager.SystemSettings.Set(Constants.GitInstallPathKey, value); + Environment.GitExecutablePath = value.ToNPath(); - gitExecHasChanged = true; - } + gitExecHasChanged = true; + } - isBusy = false; + isBusy = false; - }).Start(); + }).Start(); + } } public override bool IsBusy From b6f205ab9f14968c32927d03753790de38ed546a Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 29 Mar 2018 13:19:04 -0400 Subject: [PATCH 05/31] Specifying dontUseGit when finding git --- src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs index b2031f83e..dcadd7ffb 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs @@ -120,7 +120,7 @@ public override void OnGUI() CheckEnteredGitPath(); new FindExecTask("git", Manager.CancellationToken) - .Configure(Manager.ProcessManager) + .Configure(Manager.ProcessManager, false, true) .FinallyInUI((success, ex, path) => { if (success) { From 8f3800c6e1db1eb18b1bae6cd4cb2f2d839ec855 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 29 Mar 2018 13:30:06 -0400 Subject: [PATCH 06/31] Making sure path for console matches ProcessEnvironment --- src/GitHub.Api/OutputProcessors/ProcessManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitHub.Api/OutputProcessors/ProcessManager.cs b/src/GitHub.Api/OutputProcessors/ProcessManager.cs index c85c94367..1fd86ea87 100644 --- a/src/GitHub.Api/OutputProcessors/ProcessManager.cs +++ b/src/GitHub.Api/OutputProcessors/ProcessManager.cs @@ -87,7 +87,7 @@ public void RunCommandLineWindow(NPath workingDirectory) var envVars = startInfo.EnvironmentVariables; var scriptContents = new[] { $"cd \"{envVars["GHU_WORKINGDIR"]}\"", - $"PATH=\"{envVars["GHU_FULLPATH"]}\":$PATH /bin/bash" + $"PATH=\"{envVars["GHU_FULLPATH"]}\" /bin/bash" }; environment.FileSystem.WriteAllLines(envVarFile, scriptContents); Mono.Unix.Native.Syscall.chmod(envVarFile, (Mono.Unix.Native.FilePermissions)493); // -rwxr-xr-x mode (0755) From 0237ef297cc56c09c70d609f8b6c325188baa380 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 29 Mar 2018 15:30:54 -0400 Subject: [PATCH 07/31] Tracking when git is custom vs internal --- .../Application/ApplicationManagerBase.cs | 21 ++++++++++------ .../OutputProcessors/ProcessManager.cs | 24 +++++++++++++++---- src/GitHub.Api/Platform/DefaultEnvironment.cs | 3 +++ src/GitHub.Api/Platform/IEnvironment.cs | 1 + src/GitHub.Api/Platform/ProcessEnvironment.cs | 3 +-- .../Editor/GitHub.Unity/UI/GitPathView.cs | 2 ++ .../IntegrationTestEnvironment.cs | 2 ++ 7 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 606faed2b..9a91c951d 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; +using System.Diagnostics.Eventing.Reader; using GitHub.Logging; namespace GitHub.Unity @@ -53,9 +54,9 @@ protected void Initialize() public void Run(bool firstRun) { Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory); - - var initEnvironmentTask = new ActionTask(CancellationToken, - (_, path) => InitializeEnvironment(path)) + + var initEnvironmentTask = new ActionTask(CancellationToken, + (_, values) => InitializeEnvironment((NPath)values[0], (bool)values[1])) { Affinity = TaskAffinity.UI }; isBusy = true; @@ -87,7 +88,9 @@ public void Run(bool firstRun) { if (path.IsInitialized) { - t.GetEndOfChain().Then(initEnvironmentTask, taskIsTopOfChain: true); + t.GetEndOfChain() + .Then(b => new object[] {path, true}) + .Then(initEnvironmentTask, taskIsTopOfChain: true); return; } Logger.Trace("Using portable git"); @@ -98,7 +101,9 @@ public void Run(bool firstRun) task.Progress(progressReporter.UpdateProgress); task.OnEnd += (thisTask, result, success, exception) => { - thisTask.GetEndOfChain().Then(initEnvironmentTask, taskIsTopOfChain: true); + thisTask.GetEndOfChain() + .Then(b => new object[] { result, false }) + .Then(initEnvironmentTask, taskIsTopOfChain: true); }; // append installer task to top chain @@ -204,8 +209,9 @@ protected void SetupMetrics(string unityVersion, bool firstRun) /// Initialize environment after finding where git is. This needs to run on the main thread /// /// + /// /// - private void InitializeEnvironment(NPath gitExecutablePath) + private void InitializeEnvironment(NPath gitExecutablePath, bool isCustomGitExec) { isBusy = false; SetupMetrics(); @@ -216,6 +222,7 @@ private void InitializeEnvironment(NPath gitExecutablePath) } Environment.GitExecutablePath = gitExecutablePath; + Environment.IsCustomGitExecutable = isCustomGitExec; Environment.User.Initialize(GitClient); var afterGitSetup = new ActionTask(CancellationToken, RestartRepository) @@ -226,7 +233,7 @@ private void InitializeEnvironment(NPath gitExecutablePath) { var credHelperTask = GitClient.GetConfig("credential.helper", GitConfigSource.Global); credHelperTask.OnEnd += (thisTask, credentialHelper, success, exception) => - { + { if (!success || string.IsNullOrEmpty(credentialHelper)) { Logger.Warning("No Windows CredentialHelper found: Setting to wincred"); diff --git a/src/GitHub.Api/OutputProcessors/ProcessManager.cs b/src/GitHub.Api/OutputProcessors/ProcessManager.cs index 1fd86ea87..b1f790bba 100644 --- a/src/GitHub.Api/OutputProcessors/ProcessManager.cs +++ b/src/GitHub.Api/OutputProcessors/ProcessManager.cs @@ -1,5 +1,6 @@ using GitHub.Logging; using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; @@ -29,7 +30,18 @@ public T Configure(T processTask, NPath? executable = null, string arguments bool dontSetupGit = false) where T : IProcess { - executable = executable ?? processTask.ProcessName?.ToNPath() ?? environment.GitExecutablePath; + if (executable == null) + { + if (processTask.ProcessName?.ToNPath() != null) + { + executable = processTask.ProcessName.ToNPath(); + } + else + { + executable = environment.GitExecutablePath; + dontSetupGit = environment.IsCustomGitExecutable; + } + } //If this null check fails, be sure you called Configure() on your task Guard.ArgumentNotNull(executable, nameof(executable)); @@ -85,11 +97,15 @@ public void RunCommandLineWindow(NPath workingDirectory) gitEnvironment.Configure(startInfo, workingDirectory); var envVars = startInfo.EnvironmentVariables; - var scriptContents = new[] { + var scriptContents = new List { $"cd \"{envVars["GHU_WORKINGDIR"]}\"", - $"PATH=\"{envVars["GHU_FULLPATH"]}\" /bin/bash" }; - environment.FileSystem.WriteAllLines(envVarFile, scriptContents); + + if (!environment.IsCustomGitExecutable) { + scriptContents.Add($"PATH=\"{envVars["GHU_FULLPATH"]}\" /bin/bash"); + } + + environment.FileSystem.WriteAllLines(envVarFile, scriptContents.ToArray()); Mono.Unix.Native.Syscall.chmod(envVarFile, (Mono.Unix.Native.FilePermissions)493); // -rwxr-xr-x mode (0755) } else diff --git a/src/GitHub.Api/Platform/DefaultEnvironment.cs b/src/GitHub.Api/Platform/DefaultEnvironment.cs index 253052ca2..26e8cc130 100644 --- a/src/GitHub.Api/Platform/DefaultEnvironment.cs +++ b/src/GitHub.Api/Platform/DefaultEnvironment.cs @@ -147,6 +147,9 @@ public NPath OctorunScriptPath octorunScriptPath = value; } } + + public bool IsCustomGitExecutable { get; set; } + public NPath GitExecutablePath { get { return gitExecutablePath; } diff --git a/src/GitHub.Api/Platform/IEnvironment.cs b/src/GitHub.Api/Platform/IEnvironment.cs index 2a8d85105..6894791cd 100644 --- a/src/GitHub.Api/Platform/IEnvironment.cs +++ b/src/GitHub.Api/Platform/IEnvironment.cs @@ -12,6 +12,7 @@ public interface IEnvironment NPath Path { get; } string NewLine { get; } + bool IsCustomGitExecutable { get; set; } NPath GitExecutablePath { get; set; } NPath NodeJsExecutablePath { get; } NPath OctorunScriptPath { get; set; } diff --git a/src/GitHub.Api/Platform/ProcessEnvironment.cs b/src/GitHub.Api/Platform/ProcessEnvironment.cs index aaff796a4..941795a59 100644 --- a/src/GitHub.Api/Platform/ProcessEnvironment.cs +++ b/src/GitHub.Api/Platform/ProcessEnvironment.cs @@ -20,12 +20,12 @@ public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSet psi.WorkingDirectory = workingDirectory; psi.EnvironmentVariables["HOME"] = NPath.HomeDirectory; psi.EnvironmentVariables["TMP"] = psi.EnvironmentVariables["TEMP"] = NPath.SystemTemp; + psi.EnvironmentVariables["GHU_WORKINGDIR"] = workingDirectory; // if we don't know where git is, then there's nothing else to configure if (!Environment.GitInstallPath.IsInitialized || dontSetupGit) return; - Guard.ArgumentNotNull(psi, "psi"); // We need to essentially fake up what git-cmd.bat does @@ -77,7 +77,6 @@ public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSet psi.EnvironmentVariables["PATH"] = path; psi.EnvironmentVariables["GHU_FULLPATH"] = path; - psi.EnvironmentVariables["GHU_WORKINGDIR"] = workingDirectory; psi.EnvironmentVariables["PLINK_PROTOCOL"] = "ssh"; psi.EnvironmentVariables["TERM"] = "msys"; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs index d852e4054..fb0b00185 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs @@ -255,6 +255,7 @@ private void ValidateAndSetGitInstallPath(string value) { Manager.SystemSettings.Unset(Constants.GitInstallPathKey); Environment.GitExecutablePath = result; + Environment.IsCustomGitExecutable = false; gitExecHasChanged = true; } @@ -323,6 +324,7 @@ private void ValidateAndSetGitInstallPath(string value) Manager.SystemSettings.Set(Constants.GitInstallPathKey, value); Environment.GitExecutablePath = value.ToNPath(); + Environment.IsCustomGitExecutable = true; gitExecHasChanged = true; } diff --git a/src/tests/IntegrationTests/IntegrationTestEnvironment.cs b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs index 113346da9..47137e44c 100644 --- a/src/tests/IntegrationTests/IntegrationTestEnvironment.cs +++ b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs @@ -88,6 +88,8 @@ public string GetSpecialFolder(Environment.SpecialFolder folder) public string NewLine => Environment.NewLine; public string UnityVersion => "5.6"; + public bool IsCustomGitExecutable { get; set; } + public NPath GitExecutablePath { get { return defaultEnvironment.GitExecutablePath; } From 240dc8126369fb9cf076945f5b65cb477add690a Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 29 Mar 2018 17:01:52 -0400 Subject: [PATCH 08/31] Attempting to not change the PATH variable when validating git --- .../Application/ApplicationManagerBase.cs | 14 ++++++-------- src/GitHub.Api/Git/GitClient.cs | 10 ++++++---- src/GitHub.Api/OutputProcessors/ProcessManager.cs | 3 +++ src/GitHub.Api/Platform/ProcessEnvironment.cs | 2 ++ .../Assets/Editor/GitHub.Unity/UI/GitPathView.cs | 2 +- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 9a91c951d..2db2b9bd7 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -1,9 +1,7 @@ using System; -using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; -using System.Diagnostics.Eventing.Reader; using GitHub.Logging; namespace GitHub.Unity @@ -55,8 +53,8 @@ public void Run(bool firstRun) { Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory); - var initEnvironmentTask = new ActionTask(CancellationToken, - (_, values) => InitializeEnvironment((NPath)values[0], (bool)values[1])) + var initEnvironmentTask = new ActionTask(CancellationToken, + (_, path) => InitializeEnvironment(path)) { Affinity = TaskAffinity.UI }; isBusy = true; @@ -89,7 +87,6 @@ public void Run(bool firstRun) if (path.IsInitialized) { t.GetEndOfChain() - .Then(b => new object[] {path, true}) .Then(initEnvironmentTask, taskIsTopOfChain: true); return; } @@ -102,7 +99,6 @@ public void Run(bool firstRun) task.OnEnd += (thisTask, result, success, exception) => { thisTask.GetEndOfChain() - .Then(b => new object[] { result, false }) .Then(initEnvironmentTask, taskIsTopOfChain: true); }; @@ -209,9 +205,8 @@ protected void SetupMetrics(string unityVersion, bool firstRun) /// Initialize environment after finding where git is. This needs to run on the main thread /// /// - /// /// - private void InitializeEnvironment(NPath gitExecutablePath, bool isCustomGitExec) + private void InitializeEnvironment(NPath gitExecutablePath) { isBusy = false; SetupMetrics(); @@ -220,6 +215,9 @@ private void InitializeEnvironment(NPath gitExecutablePath, bool isCustomGitExec { return; } + + var gitInstallDetails = new GitInstaller.GitInstallDetails(Environment.UserCachePath, Environment.IsWindows); + var isCustomGitExec = gitExecutablePath != gitInstallDetails.GitExecutablePath; Environment.GitExecutablePath = gitExecutablePath; Environment.IsCustomGitExecutable = isCustomGitExec; diff --git a/src/GitHub.Api/Git/GitClient.cs b/src/GitHub.Api/Git/GitClient.cs index c7439b504..f0dc0a0d2 100644 --- a/src/GitHub.Api/Git/GitClient.cs +++ b/src/GitHub.Api/Git/GitClient.cs @@ -9,7 +9,7 @@ namespace GitHub.Unity { public interface IGitClient { - ITask ValidateGitInstall(NPath path); + ITask ValidateGitInstall(NPath path, bool isCustomGit); ITask Init(IOutputProcessor processor = null); @@ -110,7 +110,7 @@ public GitClient(IEnvironment environment, IProcessManager processManager, Cance this.cancellationToken = cancellationToken; } - public ITask ValidateGitInstall(NPath path) + public ITask ValidateGitInstall(NPath path, bool isCustomGit) { if (!path.FileExists()) { @@ -126,7 +126,8 @@ public ITask ValidateGitInstall(NPath path) gitLfsVersion?.CompareTo(Constants.MinimumGitLfsVersion) >= 0, gitVersion, gitLfsVersion)); - var gitLfsVersionTask = new GitLfsVersionTask(cancellationToken).Configure(processManager, path); + var gitLfsVersionTask = new GitLfsVersionTask(cancellationToken) + .Configure(processManager, path, dontSetupGit: isCustomGit); gitLfsVersionTask .Then((result, version) => {return gitLfsVersion = version;}) @@ -134,7 +135,8 @@ public ITask ValidateGitInstall(NPath path) gitLfsVersionTask.Then(endTask, TaskRunOptions.OnFailure, taskIsTopOfChain:true); - var gitVersionTask = new GitVersionTask(cancellationToken).Configure(processManager, path); + var gitVersionTask = new GitVersionTask(cancellationToken) + .Configure(processManager, path, dontSetupGit: isCustomGit); gitVersionTask .Then((result, version) => { return gitVersion = version; }) diff --git a/src/GitHub.Api/OutputProcessors/ProcessManager.cs b/src/GitHub.Api/OutputProcessors/ProcessManager.cs index b1f790bba..dba3ce4a8 100644 --- a/src/GitHub.Api/OutputProcessors/ProcessManager.cs +++ b/src/GitHub.Api/OutputProcessors/ProcessManager.cs @@ -30,6 +30,8 @@ public T Configure(T processTask, NPath? executable = null, string arguments bool dontSetupGit = false) where T : IProcess { + logger.Trace("Configure executable:{0}", executable); + if (executable == null) { if (processTask.ProcessName?.ToNPath() != null) @@ -57,6 +59,7 @@ public T Configure(T processTask, NPath? executable = null, string arguments StandardErrorEncoding = Encoding.UTF8 }; + logger.Trace("gitEnvironment.Configure dontSetupGit:{0}", dontSetupGit); gitEnvironment.Configure(startInfo, workingDirectory ?? environment.RepositoryPath, dontSetupGit); if (executable.Value.IsRelative) diff --git a/src/GitHub.Api/Platform/ProcessEnvironment.cs b/src/GitHub.Api/Platform/ProcessEnvironment.cs index 941795a59..78f83d081 100644 --- a/src/GitHub.Api/Platform/ProcessEnvironment.cs +++ b/src/GitHub.Api/Platform/ProcessEnvironment.cs @@ -21,6 +21,8 @@ public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSet psi.EnvironmentVariables["HOME"] = NPath.HomeDirectory; psi.EnvironmentVariables["TMP"] = psi.EnvironmentVariables["TEMP"] = NPath.SystemTemp; psi.EnvironmentVariables["GHU_WORKINGDIR"] = workingDirectory; + + Logger.Trace("Configure DontSetupGit:{0}", dontSetupGit); // if we don't know where git is, then there's nothing else to configure if (!Environment.GitInstallPath.IsInitialized || dontSetupGit) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs index fb0b00185..057b27222 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs @@ -269,7 +269,7 @@ private void ValidateAndSetGitInstallPath(string value) gitVersionErrorMessage = null; - GitClient.ValidateGitInstall(value.ToNPath()) + GitClient.ValidateGitInstall(value.ToNPath(), true) .FinallyInUI((success, exception, result) => { if (!success) From f34016b299c00f806a43b189bdbd33aced59e2b2 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 29 Mar 2018 17:12:18 -0400 Subject: [PATCH 09/31] Fixing the load of the terminal and logging default system path --- src/GitHub.Api/OutputProcessors/ProcessManager.cs | 9 ++++++--- src/GitHub.Api/Platform/ProcessEnvironment.cs | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/GitHub.Api/OutputProcessors/ProcessManager.cs b/src/GitHub.Api/OutputProcessors/ProcessManager.cs index dba3ce4a8..051303cf3 100644 --- a/src/GitHub.Api/OutputProcessors/ProcessManager.cs +++ b/src/GitHub.Api/OutputProcessors/ProcessManager.cs @@ -87,7 +87,7 @@ public void RunCommandLineWindow(NPath workingDirectory) if (environment.IsWindows) { startInfo.FileName = "cmd"; - gitEnvironment.Configure(startInfo, workingDirectory); + gitEnvironment.Configure(startInfo, workingDirectory, environment.IsCustomGitExecutable); } else if (environment.IsMac) { @@ -97,7 +97,7 @@ public void RunCommandLineWindow(NPath workingDirectory) var envVarFile = NPath.GetTempFilename(); startInfo.FileName = "open"; startInfo.Arguments = $"-a Terminal {envVarFile}"; - gitEnvironment.Configure(startInfo, workingDirectory); + gitEnvironment.Configure(startInfo, workingDirectory, environment.IsCustomGitExecutable); var envVars = startInfo.EnvironmentVariables; var scriptContents = new List { @@ -107,6 +107,9 @@ public void RunCommandLineWindow(NPath workingDirectory) if (!environment.IsCustomGitExecutable) { scriptContents.Add($"PATH=\"{envVars["GHU_FULLPATH"]}\" /bin/bash"); } + else { + scriptContents.Add($"/bin/bash"); + } environment.FileSystem.WriteAllLines(envVarFile, scriptContents.ToArray()); Mono.Unix.Native.Syscall.chmod(envVarFile, (Mono.Unix.Native.FilePermissions)493); // -rwxr-xr-x mode (0755) @@ -114,7 +117,7 @@ public void RunCommandLineWindow(NPath workingDirectory) else { startInfo.FileName = "sh"; - gitEnvironment.Configure(startInfo, workingDirectory); + gitEnvironment.Configure(startInfo, workingDirectory, environment.IsCustomGitExecutable); } Process.Start(startInfo); diff --git a/src/GitHub.Api/Platform/ProcessEnvironment.cs b/src/GitHub.Api/Platform/ProcessEnvironment.cs index 78f83d081..5f8af2364 100644 --- a/src/GitHub.Api/Platform/ProcessEnvironment.cs +++ b/src/GitHub.Api/Platform/ProcessEnvironment.cs @@ -22,6 +22,8 @@ public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSet psi.EnvironmentVariables["TMP"] = psi.EnvironmentVariables["TEMP"] = NPath.SystemTemp; psi.EnvironmentVariables["GHU_WORKINGDIR"] = workingDirectory; + + Logger.Trace("Default System PATH:{0}", Environment.GetEnvironmentVariable("PATH")); Logger.Trace("Configure DontSetupGit:{0}", dontSetupGit); // if we don't know where git is, then there's nothing else to configure From 7a52d981ffcb008a8210b8dc98a8aa98df5485d4 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 2 Apr 2018 09:27:36 -0400 Subject: [PATCH 10/31] Making some code more like the original --- src/GitHub.Api/OutputProcessors/ProcessManager.cs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/GitHub.Api/OutputProcessors/ProcessManager.cs b/src/GitHub.Api/OutputProcessors/ProcessManager.cs index 051303cf3..d95384da2 100644 --- a/src/GitHub.Api/OutputProcessors/ProcessManager.cs +++ b/src/GitHub.Api/OutputProcessors/ProcessManager.cs @@ -100,18 +100,11 @@ public void RunCommandLineWindow(NPath workingDirectory) gitEnvironment.Configure(startInfo, workingDirectory, environment.IsCustomGitExecutable); var envVars = startInfo.EnvironmentVariables; - var scriptContents = new List { + var scriptContents = new[] { $"cd \"{envVars["GHU_WORKINGDIR"]}\"", + environment.IsCustomGitExecutable? "/bin/bash" : $"PATH=\"{envVars["GHU_FULLPATH"]}\":$PATH /bin/bash" }; - - if (!environment.IsCustomGitExecutable) { - scriptContents.Add($"PATH=\"{envVars["GHU_FULLPATH"]}\" /bin/bash"); - } - else { - scriptContents.Add($"/bin/bash"); - } - - environment.FileSystem.WriteAllLines(envVarFile, scriptContents.ToArray()); + environment.FileSystem.WriteAllLines(envVarFile, scriptContents); Mono.Unix.Native.Syscall.chmod(envVarFile, (Mono.Unix.Native.FilePermissions)493); // -rwxr-xr-x mode (0755) } else From 0f551336e29bd9fb590ff26c21940b337de0e9eb Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 2 Apr 2018 09:27:52 -0400 Subject: [PATCH 11/31] Commenting log message --- src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs index 057b27222..e995fb990 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs @@ -265,7 +265,7 @@ private void ValidateAndSetGitInstallPath(string value) } else { - Logger.Trace("Validating Git Path:{0}", value); + //Logger.Trace("Validating Git Path:{0}", value); gitVersionErrorMessage = null; From 3dd3616d1ed686988a56d10d548e990234d9d545 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 2 Apr 2018 10:40:50 -0400 Subject: [PATCH 12/31] Updating the Environment path with the output of path_helper --- .../Application/ApplicationManagerBase.cs | 22 ++++- src/GitHub.Api/Platform/DefaultEnvironment.cs | 3 +- src/GitHub.Api/Platform/IEnvironment.cs | 2 +- src/GitHub.Api/Platform/ProcessEnvironment.cs | 89 +++++++------------ .../IntegrationTestEnvironment.cs | 3 +- 5 files changed, 60 insertions(+), 59 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 2db2b9bd7..775587061 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -52,6 +52,26 @@ protected void Initialize() public void Run(bool firstRun) { Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory); + + ITask getMacEnvironmentPathTask; + if (Environment.IsMac) + { + getMacEnvironmentPathTask = new SimpleProcessTask(CancellationToken, "bash".ToNPath(), "-c \"/usr/libexec/path_helper\"") + .Configure(ProcessManager) + .Then((success, path) => success ? path.Split(new[] { "\"" }, StringSplitOptions.None)[1] : null); + } + else + { + getMacEnvironmentPathTask = new FuncTask(CancellationToken, () => null); + } + + var setMacEnvironmentPathTask = getMacEnvironmentPathTask.Then((_, path) => { + if (path != null) + { + Logger.Trace("Mac Environment Path Original:{0} Updated:{1}", Environment.Path, path); + Environment.Path = path; + } + }); var initEnvironmentTask = new ActionTask(CancellationToken, (_, path) => InitializeEnvironment(path)) @@ -60,7 +80,7 @@ public void Run(bool firstRun) isBusy = true; var octorunInstaller = new OctorunInstaller(Environment, TaskManager); - var setupTask = octorunInstaller.SetupOctorunIfNeeded(); + var setupTask = setMacEnvironmentPathTask.Then(octorunInstaller.SetupOctorunIfNeeded()); var initializeGitTask = new FuncTask(CancellationToken, () => { diff --git a/src/GitHub.Api/Platform/DefaultEnvironment.cs b/src/GitHub.Api/Platform/DefaultEnvironment.cs index 26e8cc130..ad385f75f 100644 --- a/src/GitHub.Api/Platform/DefaultEnvironment.cs +++ b/src/GitHub.Api/Platform/DefaultEnvironment.cs @@ -132,7 +132,8 @@ public string GetEnvironmentVariable(string variable) public NPath ExtensionInstallPath { get; set; } public NPath UserCachePath { get; set; } public NPath SystemCachePath { get; set; } - public NPath Path => Environment.GetEnvironmentVariable("PATH").ToNPath(); + public string Path { get; set; } = Environment.GetEnvironmentVariable("PATH"); + public string NewLine => Environment.NewLine; public NPath OctorunScriptPath { diff --git a/src/GitHub.Api/Platform/IEnvironment.cs b/src/GitHub.Api/Platform/IEnvironment.cs index 6894791cd..3be9a6ae4 100644 --- a/src/GitHub.Api/Platform/IEnvironment.cs +++ b/src/GitHub.Api/Platform/IEnvironment.cs @@ -10,7 +10,7 @@ public interface IEnvironment string GetEnvironmentVariable(string v); string GetSpecialFolder(Environment.SpecialFolder folder); - NPath Path { get; } + string Path { get; set; } string NewLine { get; } bool IsCustomGitExecutable { get; set; } NPath GitExecutablePath { get; set; } diff --git a/src/GitHub.Api/Platform/ProcessEnvironment.cs b/src/GitHub.Api/Platform/ProcessEnvironment.cs index 5f8af2364..3e40effb1 100644 --- a/src/GitHub.Api/Platform/ProcessEnvironment.cs +++ b/src/GitHub.Api/Platform/ProcessEnvironment.cs @@ -17,81 +17,60 @@ public ProcessEnvironment(IEnvironment environment) public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSetupGit = false) { + Guard.ArgumentNotNull(psi, "psi"); + psi.WorkingDirectory = workingDirectory; psi.EnvironmentVariables["HOME"] = NPath.HomeDirectory; psi.EnvironmentVariables["TMP"] = psi.EnvironmentVariables["TEMP"] = NPath.SystemTemp; psi.EnvironmentVariables["GHU_WORKINGDIR"] = workingDirectory; - - - Logger.Trace("Default System PATH:{0}", Environment.GetEnvironmentVariable("PATH")); - Logger.Trace("Configure DontSetupGit:{0}", dontSetupGit); + psi.EnvironmentVariables["PATH"] = Environment.Path; + psi.EnvironmentVariables["GHU_FULLPATH"] = Environment.Path; // if we don't know where git is, then there's nothing else to configure if (!Environment.GitInstallPath.IsInitialized || dontSetupGit) return; - - Guard.ArgumentNotNull(psi, "psi"); - - // We need to essentially fake up what git-cmd.bat does - - var gitPathRoot = Environment.GitInstallPath; - var gitLfsPath = Environment.GitInstallPath; - var gitExecutableDir = Environment.GitExecutablePath.Parent; // original path to git (might be different from install path if it's a symlink) - - Logger.Trace("Environment.GitExecutablePath: {0}", Environment.GitExecutablePath); - - // Paths to developer tools such as msbuild.exe - //var developerPaths = StringExtensions.JoinForAppending(";", developerEnvironment.GetPaths()); - var developerPaths = ""; - + + var httpProxy = Environment.GetEnvironmentVariable("HTTP_PROXY"); + if (!String.IsNullOrEmpty(httpProxy)) + psi.EnvironmentVariables["HTTP_PROXY"] = httpProxy; + + var httpsProxy = Environment.GetEnvironmentVariable("HTTPS_PROXY"); + if (!String.IsNullOrEmpty(httpsProxy)) + psi.EnvironmentVariables["HTTPS_PROXY"] = httpsProxy; + //TODO: Remove with Git LFS Locking becomes standard psi.EnvironmentVariables["GITLFSLOCKSENABLED"] = "1"; - string path; - var baseExecPath = gitPathRoot; - var binPath = baseExecPath; if (Environment.IsWindows) { + // We need to essentially fake up what git-cmd.bat does + var gitPathRoot = Environment.GitInstallPath; + + var baseExecPath = gitPathRoot; if (baseExecPath.DirectoryExists("mingw32")) baseExecPath = baseExecPath.Combine("mingw32"); else baseExecPath = baseExecPath.Combine("mingw64"); - binPath = baseExecPath.Combine("bin"); - } - - var execPath = baseExecPath.Combine("libexec", "git-core"); - if (!execPath.DirectoryExists()) - execPath = NPath.Default; + var binPath = baseExecPath.Combine("bin"); + + var execPath = baseExecPath.Combine("libexec", "git-core"); + if (!execPath.DirectoryExists()) + execPath = NPath.Default; - if (Environment.IsWindows) - { var userPath = @"C:\windows\system32;C:\windows"; - path = $"{gitPathRoot}\\cmd;{gitPathRoot}\\usr\\bin;{execPath};{binPath};{gitLfsPath};{userPath}{developerPaths}"; - } - else - { - path = $"{gitExecutableDir}:{binPath}:{execPath}:{gitLfsPath}:{Environment.Path}:{developerPaths}"; + var path = $"{gitPathRoot}\\cmd;{gitPathRoot}\\usr\\bin;{execPath};{binPath}"; + + Logger.Trace("Calculated Path: {0}", path); + + if (execPath.IsInitialized) + psi.EnvironmentVariables["GIT_EXEC_PATH"] = execPath.ToString(); + + psi.EnvironmentVariables["PATH"] = path; + psi.EnvironmentVariables["GHU_FULLPATH"] = path; + + psi.EnvironmentVariables["PLINK_PROTOCOL"] = "ssh"; + psi.EnvironmentVariables["TERM"] = "msys"; } - - Logger.Trace("Environment Path: {0}", Environment.Path); - Logger.Trace("Calculated Path: {0}", path); - - if (execPath.IsInitialized) - psi.EnvironmentVariables["GIT_EXEC_PATH"] = execPath.ToString(); - - psi.EnvironmentVariables["PATH"] = path; - psi.EnvironmentVariables["GHU_FULLPATH"] = path; - - psi.EnvironmentVariables["PLINK_PROTOCOL"] = "ssh"; - psi.EnvironmentVariables["TERM"] = "msys"; - - var httpProxy = Environment.GetEnvironmentVariable("HTTP_PROXY"); - if (!String.IsNullOrEmpty(httpProxy)) - psi.EnvironmentVariables["HTTP_PROXY"] = httpProxy; - - var httpsProxy = Environment.GetEnvironmentVariable("HTTPS_PROXY"); - if (!String.IsNullOrEmpty(httpsProxy)) - psi.EnvironmentVariables["HTTPS_PROXY"] = httpsProxy; } } } \ No newline at end of file diff --git a/src/tests/IntegrationTests/IntegrationTestEnvironment.cs b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs index 47137e44c..36937d56f 100644 --- a/src/tests/IntegrationTests/IntegrationTestEnvironment.cs +++ b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs @@ -84,7 +84,8 @@ public string GetSpecialFolder(Environment.SpecialFolder folder) public string UserProfilePath => UserCachePath.Parent.CreateDirectory("user profile path"); - public NPath Path => Environment.GetEnvironmentVariable("PATH").ToNPath(); + public string Path { get; set; } = Environment.GetEnvironmentVariable("PATH").ToNPath(); + public string NewLine => Environment.NewLine; public string UnityVersion => "5.6"; From 57e18a5a3a42641979b81ffa778eba40149f6819 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 2 Apr 2018 11:10:58 -0400 Subject: [PATCH 13/31] Removing vim stackdump --- vim.exe.stackdump | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 vim.exe.stackdump diff --git a/vim.exe.stackdump b/vim.exe.stackdump deleted file mode 100644 index 8099f8995..000000000 --- a/vim.exe.stackdump +++ /dev/null @@ -1,19 +0,0 @@ -Stack trace: -Frame Function Args -00180238000 0018005D19E (00180223639, 00180223C39, 001802342F0, 000FFFFB690) -00180238000 001800463F9 (C0C0C000008080, FF000000808080, FFFF000000FF00, FF00FF000000FF) -00180238000 00180046432 (00180223616, 000000001E7, 001802342F0, 80808000C0C0C0) -00180238000 001800431E3 (00000000000, 00180238000, 7FF92F90D6DE, 001800004EC) -00180238000 0018006B101 (C0C0C000008080, FF000000808080, FFFF000000FF00, FF00FF000000FF) -00180238000 0018006BF4C (00000000000, 0010065D548, 00000000000, 00000000000) -00180238000 0018006E066 (00000000000, 00000000008, 005FCB3E280, 00000000000) -00000000001 00180135376 (0010065D540, 00000000008, 00000000000, 00000000000) -00000000001 0018011C6FB (0010065D540, 00000000008, 00000000000, 00000000000) -00000000001 001004F77E4 (00100575E0A, 00100663D08, 00000000000, 00100663D0C) -00000000001 001005820F3 (00000000008, 00100664140, 00000000000, 00000000000) -00000000001 00100576D86 (000241E9F28, 0005A6893D4, 000241E9F28, 00000010000) -00000000001 001005D4CEB (00000000000, 00000000000, 0000000000B, 000FFFFCBD0) -0060004F000 001005E218A (00000000043, 000FFFFCC54, 00000000030, 30001000000FF00) -000FFFFCCB0 001800479F7 (00000000000, 00000000000, 00000000000, 00000000000) -00000000000 00180045663 (00000000000, 00000000000, 00000000000, 00000000000) -End of stack trace (more stack frames may be present) From 1a514a76354c274da5bb123f58a690cad4a651f5 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 2 Apr 2018 16:02:33 -0400 Subject: [PATCH 14/31] Removing some log messages --- src/GitHub.Api/OutputProcessors/ProcessManager.cs | 3 --- src/GitHub.Api/Platform/ProcessEnvironment.cs | 2 -- 2 files changed, 5 deletions(-) diff --git a/src/GitHub.Api/OutputProcessors/ProcessManager.cs b/src/GitHub.Api/OutputProcessors/ProcessManager.cs index d95384da2..6498e285c 100644 --- a/src/GitHub.Api/OutputProcessors/ProcessManager.cs +++ b/src/GitHub.Api/OutputProcessors/ProcessManager.cs @@ -30,8 +30,6 @@ public T Configure(T processTask, NPath? executable = null, string arguments bool dontSetupGit = false) where T : IProcess { - logger.Trace("Configure executable:{0}", executable); - if (executable == null) { if (processTask.ProcessName?.ToNPath() != null) @@ -59,7 +57,6 @@ public T Configure(T processTask, NPath? executable = null, string arguments StandardErrorEncoding = Encoding.UTF8 }; - logger.Trace("gitEnvironment.Configure dontSetupGit:{0}", dontSetupGit); gitEnvironment.Configure(startInfo, workingDirectory ?? environment.RepositoryPath, dontSetupGit); if (executable.Value.IsRelative) diff --git a/src/GitHub.Api/Platform/ProcessEnvironment.cs b/src/GitHub.Api/Platform/ProcessEnvironment.cs index 3e40effb1..0f58ba8fa 100644 --- a/src/GitHub.Api/Platform/ProcessEnvironment.cs +++ b/src/GitHub.Api/Platform/ProcessEnvironment.cs @@ -60,8 +60,6 @@ public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSet var userPath = @"C:\windows\system32;C:\windows"; var path = $"{gitPathRoot}\\cmd;{gitPathRoot}\\usr\\bin;{execPath};{binPath}"; - Logger.Trace("Calculated Path: {0}", path); - if (execPath.IsInitialized) psi.EnvironmentVariables["GIT_EXEC_PATH"] = execPath.ToString(); From 1e0210205656ca0b32fb8f8897a53d2b2a2c47a8 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Tue, 3 Apr 2018 20:33:24 +0200 Subject: [PATCH 15/31] Simplify getting the environment path initially --- .../Application/ApplicationManagerBase.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 775587061..2b2732ed3 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -53,25 +53,25 @@ public void Run(bool firstRun) { Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory); - ITask getMacEnvironmentPathTask; + ITask setExistingEnvironmentPath; if (Environment.IsMac) { - getMacEnvironmentPathTask = new SimpleProcessTask(CancellationToken, "bash".ToNPath(), "-c \"/usr/libexec/path_helper\"") - .Configure(ProcessManager) + setExistingEnvironmentPath = new SimpleProcessTask(CancellationToken, "bash".ToNPath(), "-c \"/usr/libexec/path_helper\"") + .Configure(ProcessManager, dontSetupGit: true) .Then((success, path) => success ? path.Split(new[] { "\"" }, StringSplitOptions.None)[1] : null); } else { - getMacEnvironmentPathTask = new FuncTask(CancellationToken, () => null); + setExistingEnvironmentPath = new FuncTask(CancellationToken, () => null); } - var setMacEnvironmentPathTask = getMacEnvironmentPathTask.Then((_, path) => { + setExistingEnvironmentPath.OnEnd += (t, path, success, ex) => { if (path != null) { - Logger.Trace("Mac Environment Path Original:{0} Updated:{1}", Environment.Path, path); + Logger.Trace("Existing Environment Path Original:{0} Updated:{1}", Environment.Path, path); Environment.Path = path; } - }); + }; var initEnvironmentTask = new ActionTask(CancellationToken, (_, path) => InitializeEnvironment(path)) @@ -80,7 +80,7 @@ public void Run(bool firstRun) isBusy = true; var octorunInstaller = new OctorunInstaller(Environment, TaskManager); - var setupTask = setMacEnvironmentPathTask.Then(octorunInstaller.SetupOctorunIfNeeded()); + var setupTask = setExistingEnvironmentPath.Then(octorunInstaller.SetupOctorunIfNeeded()); var initializeGitTask = new FuncTask(CancellationToken, () => { From 7b08073c36044bdbe316504e861db1a68b625de2 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Tue, 3 Apr 2018 20:37:02 +0200 Subject: [PATCH 16/31] If running bash fails, don't fail the whole chain, ignore the error and continue --- src/GitHub.Api/Application/ApplicationManagerBase.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 2b2732ed3..06869d777 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -58,6 +58,7 @@ public void Run(bool firstRun) { setExistingEnvironmentPath = new SimpleProcessTask(CancellationToken, "bash".ToNPath(), "-c \"/usr/libexec/path_helper\"") .Configure(ProcessManager, dontSetupGit: true) + .Catch(e => true) // make sure this doesn't throw if the task fails .Then((success, path) => success ? path.Split(new[] { "\"" }, StringSplitOptions.None)[1] : null); } else From acfe26841b648b1a112abb486d1e15fd766e330f Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 4 Apr 2018 15:02:36 +0200 Subject: [PATCH 17/31] Fix a bunch of stuff in the git installation process - Fix a bunch of typos - Make sure the download failing doesn't abort the whole process - Install lfs if there is a git but lfs is missing - Fix the download tests to download the real files that we're shipping - Mock the unzipper for the git installer test so it's faster - a bunch of other fixes --- .../Application/ApplicationManagerBase.cs | 16 +- src/GitHub.Api/Installer/GitInstaller.cs | 198 +++++++++++------- src/GitHub.Api/Installer/ZipHelper.cs | 1 + src/GitHub.Api/Managers/Downloader.cs | 55 +++-- .../OutputProcessors/ProcessManager.cs | 8 +- src/GitHub.Api/Platform/DefaultEnvironment.cs | 13 ++ src/GitHub.Api/Platform/IEnvironment.cs | 2 + src/GitHub.Api/Platform/ProcessEnvironment.cs | 99 +++++---- src/GitHub.Api/Tasks/ProcessTask.cs | 2 +- .../Editor/GitHub.Unity/UI/GitPathView.cs | 6 +- .../IntegrationTests/BaseIntegrationTest.cs | 15 +- .../Download/DownloadTaskTests.cs | 38 ++-- .../Installer/GitInstallerTests.cs | 83 +++++++- .../IntegrationTestEnvironment.cs | 2 + src/tests/TestWebServer/TestWebServer.csproj | 34 +++ 15 files changed, 402 insertions(+), 170 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 06869d777..31bf7f5fd 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -74,8 +74,8 @@ public void Run(bool firstRun) } }; - var initEnvironmentTask = new ActionTask(CancellationToken, - (_, path) => InitializeEnvironment(path)) + var initEnvironmentTask = new ActionTask(CancellationToken, + (_, state) => InitializeEnvironment(state)) { Affinity = TaskAffinity.UI }; isBusy = true; @@ -227,20 +227,22 @@ protected void SetupMetrics(string unityVersion, bool firstRun) /// /// /// - private void InitializeEnvironment(NPath gitExecutablePath) + private void InitializeEnvironment(GitInstaller.GitInstallationState installationState) { isBusy = false; SetupMetrics(); - if (!gitExecutablePath.IsInitialized) + if (!installationState.GitIsValid) { return; } - + var gitInstallDetails = new GitInstaller.GitInstallDetails(Environment.UserCachePath, Environment.IsWindows); - var isCustomGitExec = gitExecutablePath != gitInstallDetails.GitExecutablePath; + var isCustomGitExec = installationState.GitExecutablePath != gitInstallDetails.GitExecutablePath; + + Environment.GitExecutablePath = installationState.GitExecutablePath; + Environment.GitLfsExecutablePath = installationState.GitLfsExecutablePath; - Environment.GitExecutablePath = gitExecutablePath; Environment.IsCustomGitExecutable = isCustomGitExec; Environment.User.Initialize(GitClient); diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 13ac0426f..480740656 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -14,8 +14,7 @@ class GitInstaller private readonly GitInstallDetails installDetails; private readonly IZipHelper sharpZipLibHelper; - GitInstallationState installationState; - ITask installationTask; + ITask installationTask; public GitInstaller(IEnvironment environment, IProcessManager processManager, ITaskManager taskManager, @@ -28,54 +27,70 @@ public GitInstaller(IEnvironment environment, IProcessManager processManager, this.installDetails = installDetails ?? new GitInstallDetails(environment.UserCachePath, environment.IsWindows); } - public ITask SetupGitIfNeeded() + public ITask SetupGitIfNeeded() { //Logger.Trace("SetupGitIfNeeded"); - installationTask = new FuncTask(cancellationToken, (success, path) => - { - return path; - }) + installationTask = new FuncTask(cancellationToken, (success, path) => path) { Name = "Git Installation - Complete" }; installationTask.OnStart += thisTask => thisTask.UpdateProgress(0, 100); installationTask.OnEnd += (thisTask, result, success, exception) => thisTask.UpdateProgress(100, 100); - ITask startTask = null; + ITask startTask = null; + GitInstallationState installationState = new GitInstallationState(); if (!environment.IsWindows) { - startTask = new FindExecTask("git", cancellationToken) - .Configure(processManager, false, true); - // we should doublecheck that system git is usable here - installationState = new GitInstallationState + var findTask = new FindExecTask("git", cancellationToken) + .Configure(processManager, dontSetupGit: true) + .Catch(e => true); + findTask.OnEnd += (thisTask, path, success, exception) => + { + // we should doublecheck that system git is usable here + installationState.GitIsValid = success; + if (success) + { + installationState.GitExecutablePath = path; + installationState.GitInstallationPath = path.Resolve().Parent.Parent; + } + }; + findTask.Then(new FindExecTask("git-lfs", cancellationToken) + .Configure(processManager, dontSetupGit: true)) + .Catch(e => true); + findTask.OnEnd += (thisTask, path, success, exception) => { - GitIsValid = true, - GitLfsIsValid = true + installationState.GitLfsIsValid = success; + if (success) + { + // we should doublecheck that system git is usable here + installationState.GitLfsExecutablePath = path; + installationState.GitLfsInstallationPath = path.Resolve().Parent.Parent; + } }; + startTask = findTask.Then(s => installationState); } else { - startTask = new FuncTask(cancellationToken, () => + startTask = new FuncTask(cancellationToken, () => { installationState = VerifyGitInstallation(); if (!installationState.GitIsValid && !installationState.GitLfsIsValid) installationState = GrabZipFromResources(installationState); else Logger.Trace("SetupGitIfNeeded: Skipped"); - return installDetails.GitExecutablePath; + return installationState; }) { Name = "Git Installation - Extract" }; - } - startTask.OnEnd += (thisTask, path, success, exception) => + startTask.OnEnd += (thisTask, installState, success, exception) => { - if (!installationState.GitIsValid && !installationState.GitLfsIsValid) + if (!installState.GitIsValid && !installState.GitLfsIsValid) { - if (!installationState.GitZipExists || !installationState.GitLfsZipExists) - thisTask = thisTask.Then(CreateDownloadTask(installationState)); - thisTask = thisTask.Then(ExtractPortableGit(installationState)); + if (!installState.GitZipExists || !installState.GitLfsZipExists) + thisTask = thisTask.Then(CreateDownloadTask(installState)); + thisTask = thisTask.Then(ExtractPortableGit(installState)); } - thisTask.Then(installationTask); + thisTask = thisTask.Then(installationTask); }; return startTask; @@ -84,37 +99,47 @@ public ITask SetupGitIfNeeded() private GitInstallationState VerifyGitInstallation() { var state = new GitInstallationState(); - state.GitExists = installDetails.GitExecutablePath.IsInitialized && installDetails.GitExecutablePath.FileExists(); - state.GitLfsExists = installDetails.GitLfsExecutablePath.IsInitialized && installDetails.GitLfsExecutablePath.FileExists(); + var gitExists = installDetails.GitExecutablePath.IsInitialized && installDetails.GitExecutablePath.FileExists(); + var gitLfsExists = installDetails.GitLfsExecutablePath.IsInitialized && installDetails.GitLfsExecutablePath.FileExists(); state.GitZipExists = installDetails.GitZipPath.FileExists(); state.GitLfsZipExists = installDetails.GitLfsZipPath.FileExists(); - if (state.GitExists) + if (gitExists) { var actualmd5 = installDetails.GitExecutablePath.CalculateMD5(); var expectedmd5 = environment.IsWindows ? GitInstallDetails.WindowsGitExecutableMD5 : GitInstallDetails.MacGitExecutableMD5; state.GitIsValid = expectedmd5.Equals(actualmd5, StringComparison.InvariantCultureIgnoreCase); - if (!state.GitIsValid) + if (state.GitIsValid) + { + state.GitInstallationPath = installDetails.GitInstallationPath; + state.GitExecutablePath = installDetails.GitExecutablePath; + } + else + { Logger.Trace($"Path {installDetails.GitExecutablePath} has MD5 {actualmd5} expected {expectedmd5}"); + } } else Logger.Trace($"{installDetails.GitExecutablePath} does not exist"); - if (state.GitLfsExists) + if (gitLfsExists) { var actualmd5 = installDetails.GitLfsExecutablePath.CalculateMD5(); var expectedmd5 = environment.IsWindows ? GitInstallDetails.WindowsGitLfsExecutableMD5 : GitInstallDetails.MacGitLfsExecutableMD5; state.GitLfsIsValid = expectedmd5.Equals(actualmd5, StringComparison.InvariantCultureIgnoreCase); - if (!state.GitLfsIsValid) + if (state.GitLfsIsValid) + { + state.GitLfsInstallationPath = installDetails.GitInstallationPath; + state.GitLfsExecutablePath = installDetails.GitLfsExecutablePath; + } + else + { Logger.Trace($"Path {installDetails.GitLfsExecutablePath} has MD5 {actualmd5} expected {expectedmd5}"); + } } else Logger.Trace($"{installDetails.GitLfsExecutablePath} does not exist"); - if (!state.GitZipExists) - Logger.Trace($"{installDetails.GitZipPath} does not exist"); - if (!state.GitLfsZipExists) - Logger.Trace($"{installDetails.GitLfsZipPath} does not exist"); installationTask.UpdateProgress(10, 100); return state; } @@ -138,93 +163,116 @@ private GitInstallationState GrabZipFromResources(GitInstallationState state) return state; } - private ITask CreateDownloadTask(GitInstallationState state) + private ITask CreateDownloadTask(GitInstallationState state) { var downloader = new Downloader(); - downloader.QueueDownload(installDetails.GitZipUrl, installDetails.GitZipMd5Url, installDetails.ZipPath); - downloader.QueueDownload(installDetails.GitLfsZipUrl, installDetails.GitLfsZipMd5Url, installDetails.ZipPath); - return downloader.Then((_, data) => + downloader.Catch(e => true); + if (!state.GitIsValid) + downloader.QueueDownload(installDetails.GitZipUrl, installDetails.GitZipMd5Url, installDetails.ZipPath); + if (!state.GitLfsIsValid) + downloader.QueueDownload(installDetails.GitLfsZipUrl, installDetails.GitLfsZipMd5Url, installDetails.ZipPath); + return downloader.Then((success, data) => { state.GitZipExists = installDetails.GitZipPath.FileExists(); state.GitLfsZipExists = installDetails.GitLfsZipPath.FileExists(); installationTask.UpdateProgress(40, 100); - return installDetails.ZipPath; + return state; }); } - private FuncTask ExtractPortableGit(GitInstallationState state) + private FuncTask ExtractPortableGit(GitInstallationState state) { ITask task = null; var tempZipExtractPath = NPath.CreateTempDirectory("git_zip_extract_zip_paths"); - var gitExtractPath = tempZipExtractPath.Combine("git").CreateDirectory(); - if (!state.GitIsValid) + if (state.GitZipExists && !state.GitIsValid) { - ITask unzipTask = new UnzipTask(cancellationToken, installDetails.GitZipPath, gitExtractPath, sharpZipLibHelper, - environment.FileSystem); + var gitExtractPath = tempZipExtractPath.Combine("git").CreateDirectory(); + var unzipTask = new UnzipTask(cancellationToken, installDetails.GitZipPath, + gitExtractPath, sharpZipLibHelper, + environment.FileSystem) + .Catch(e => true); unzipTask.Progress(p => installationTask.UpdateProgress(40 + (long)(20 * p.Percentage), 100, unzipTask.Name)); - unzipTask = unzipTask.Then((s, path) => + unzipTask = unzipTask.Then((success, path) => { - var source = path; var target = installDetails.GitInstallationPath; - target.DeleteIfExists(); - target.EnsureParentDirectoryExists(); - Logger.Trace($"Moving '{source}' to '{target}'"); - source.Move(target); - state.GitExists = installDetails.GitExecutablePath.FileExists(); - state.GitIsValid = s; + if (success) + { + var source = path; + target.DeleteIfExists(); + target.EnsureParentDirectoryExists(); + Logger.Trace($"Moving '{source}' to '{target}'"); + source.Move(target); + state.GitInstallationPath = installDetails.GitInstallationPath; + state.GitExecutablePath = installDetails.GitExecutablePath; + state.GitIsValid = success; + } return target; }); task = unzipTask; } - var gitLfsExtractPath = tempZipExtractPath.Combine("git-lfs").CreateDirectory(); - - if (!state.GitLfsIsValid) + if (state.GitLfsZipExists && !state.GitLfsIsValid) { - ITask unzipTask = new UnzipTask(cancellationToken, installDetails.GitLfsZipPath, gitLfsExtractPath, sharpZipLibHelper, - environment.FileSystem); + var gitLfsExtractPath = tempZipExtractPath.Combine("git-lfs").CreateDirectory(); + var unzipTask = new UnzipTask(cancellationToken, installDetails.GitLfsZipPath, + gitLfsExtractPath, sharpZipLibHelper, + environment.FileSystem) + .Catch(e => true); unzipTask.Progress(p => installationTask.UpdateProgress(60 + (long)(20 * p.Percentage), 100, unzipTask.Name)); - unzipTask = unzipTask.Then((s, path) => + unzipTask = unzipTask.Then((success, path) => { - var source = path.Combine(installDetails.GitLfsExecutable); - var target = installDetails.GetGitLfsExecutablePath(installDetails.GitInstallationPath); - target.DeleteIfExists(); - target.EnsureParentDirectoryExists(); - Logger.Trace($"Moving '{source}' to '{target}'"); - source.Move(target); - state.GitExists = target.FileExists(); - state.GitIsValid = s; + var target = installDetails.GetGitLfsExecutablePath(state.GitInstallationPath); + if (success) + { + var source = path.Combine(installDetails.GitLfsExecutable); + target.DeleteIfExists(); + target.EnsureParentDirectoryExists(); + Logger.Trace($"Moving '{source}' to '{target}'"); + source.Move(target); + state.GitLfsInstallationPath = state.GitInstallationPath; + state.GitLfsExecutablePath = target; + state.GitLfsIsValid = success; + } return target; }); task = task?.Then(unzipTask) ?? unzipTask; } - return task.Finally(new FuncTask(cancellationToken, (success) => + var endTask = new FuncTask(cancellationToken, (success) => { tempZipExtractPath.DeleteIfExists(); - return installDetails.GitExecutablePath; - })); + return state; + }); + + if (task != null) + { + endTask = task.Then(endTask); + } + + return endTask; } - class GitInstallationState + public class GitInstallationState { - public bool GitExists { get; set; } - public bool GitLfsExists { get; set; } public bool GitIsValid { get; set; } public bool GitLfsIsValid { get; set; } public bool GitZipExists { get; set; } public bool GitLfsZipExists { get; set; } + public NPath GitInstallationPath { get; set; } + public NPath GitExecutablePath { get; set; } + public NPath GitLfsInstallationPath { get; set; } + public NPath GitLfsExecutablePath { get; set; } } public class GitInstallDetails { - public const string DefaultGitZipMd5Url = "https://ghfvs-installer.github.com/unity/portable_git/git.zip.md5"; - public const string DefaultGitZipUrl = "https://ghfvs-installer.github.com/unity/portable_git/git.zip"; - public const string DefaultGitLfsZipMd5Url = "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.md5"; - public const string DefaultGitLfsZipUrl = "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip"; + public const string DefaultGitZipMd5Url = "https://ghfvs-installer.github.com/unity/git/windows/git.zip.md5"; + public const string DefaultGitZipUrl = "https://ghfvs-installer.github.com/unity/git/windows/git.zip"; + public const string DefaultGitLfsZipMd5Url = "https://ghfvs-installer.github.com/unity/git/windows/git-lfs.zip.md5"; + public const string DefaultGitLfsZipUrl = "https://ghfvs-installer.github.com/unity/git/windows/git-lfs.zip"; public const string GitExtractedMD5 = "e6cfc0c294a2312042f27f893dfc9c0a"; public const string GitLfsExtractedMD5 = "36e3ae968b69fbf42dff72311040d24a"; diff --git a/src/GitHub.Api/Installer/ZipHelper.cs b/src/GitHub.Api/Installer/ZipHelper.cs index e2465f19f..57f55ea49 100644 --- a/src/GitHub.Api/Installer/ZipHelper.cs +++ b/src/GitHub.Api/Installer/ZipHelper.cs @@ -19,6 +19,7 @@ public static IZipHelper Instance instance = new ZipHelper(); return instance; } + set { instance = value; } } public bool Extract(string archive, string outFolder, CancellationToken cancellationToken, diff --git a/src/GitHub.Api/Managers/Downloader.cs b/src/GitHub.Api/Managers/Downloader.cs index de079b14f..93bd5ead4 100644 --- a/src/GitHub.Api/Managers/Downloader.cs +++ b/src/GitHub.Api/Managers/Downloader.cs @@ -83,6 +83,8 @@ public Task Run() { foreach (var task in queuedTasks) task.Start(); + if (queuedTasks.Count == 0) + DownloadComplete(null); return aggregateDownloads.Task; } @@ -121,32 +123,55 @@ public Task QueueDownload(UriString url, UriString md5Url, NPath t var md5Exists = destinationMd5.FileExists(); var fileExists = destinationFile.FileExists(); + if (fileExists && md5Exists) + { + var verification = new FuncTask(cancellationToken, () => destinationFile); + verification.OnStart += _ => DownloadStart?.Invoke(result); + verification.OnEnd += (t, res, success, ex) => + { + if (!Utils.VerifyFileIntegrity(destinationFile, destinationMd5)) + { + destinationMd5.Delete(); + destinationFile.Delete(); + var fileDownload = DownloadFile(url, targetDirectory, result, verifyDownload); + queuedTasks.Add(fileDownload); + var md5Download = DownloadFile(md5Url, targetDirectory, result, verifyDownload); + queuedTasks.Add(md5Download); + fileDownload.Start(); + md5Download.Start(); + } + else + { + DownloadComplete(result); + } + }; + queuedTasks.Add(verification); + } + if (!md5Exists) { - destinationMd5.DeleteIfExists(); - var md5Download = new DownloadTask(cancellationToken, fs, md5Url, targetDirectory) - .Catch(e => DownloadFailed(result, e)); - md5Download.OnEnd += verifyDownload; + var md5Download = DownloadFile(md5Url, targetDirectory, result, verifyDownload); + md5Download.OnStart += _ => DownloadStart?.Invoke(result); queuedTasks.Add(md5Download); } if (!fileExists) { - var fileDownload = new DownloadTask(cancellationToken, fs, url, targetDirectory) - .Catch(e => DownloadFailed(result, e)); - fileDownload.OnStart += _ => DownloadStart?.Invoke(result); - fileDownload.OnEnd += verifyDownload; + var fileDownload = DownloadFile(url, targetDirectory, result, verifyDownload); + if (md5Exists) // only invoke DownloadStart if it hasn't been invoked before in the md5 download + fileDownload.OnStart += _ => DownloadStart?.Invoke(result); queuedTasks.Add(fileDownload); } - - if (fileExists && md5Exists) - { - var verification = new FuncTask(cancellationToken, () => destinationFile); - verification.OnEnd += verifyDownload; - queuedTasks.Add(verification); - } return aggregateDownloads.Task; } + + private ITask DownloadFile(UriString url, NPath targetDirectory, DownloadData result, Action, NPath, bool, Exception> verifyDownload) + { + var download = new DownloadTask(cancellationToken, fs, url, targetDirectory) + .Catch(e => { DownloadFailed(result, e); return true; }); + download.OnEnd += verifyDownload; + return download; + } } public static bool Download(ILogging logger, UriString url, diff --git a/src/GitHub.Api/OutputProcessors/ProcessManager.cs b/src/GitHub.Api/OutputProcessors/ProcessManager.cs index 6498e285c..23d8c009c 100644 --- a/src/GitHub.Api/OutputProcessors/ProcessManager.cs +++ b/src/GitHub.Api/OutputProcessors/ProcessManager.cs @@ -84,7 +84,7 @@ public void RunCommandLineWindow(NPath workingDirectory) if (environment.IsWindows) { startInfo.FileName = "cmd"; - gitEnvironment.Configure(startInfo, workingDirectory, environment.IsCustomGitExecutable); + gitEnvironment.Configure(startInfo, workingDirectory); } else if (environment.IsMac) { @@ -94,12 +94,12 @@ public void RunCommandLineWindow(NPath workingDirectory) var envVarFile = NPath.GetTempFilename(); startInfo.FileName = "open"; startInfo.Arguments = $"-a Terminal {envVarFile}"; - gitEnvironment.Configure(startInfo, workingDirectory, environment.IsCustomGitExecutable); + gitEnvironment.Configure(startInfo, workingDirectory); var envVars = startInfo.EnvironmentVariables; var scriptContents = new[] { $"cd \"{envVars["GHU_WORKINGDIR"]}\"", - environment.IsCustomGitExecutable? "/bin/bash" : $"PATH=\"{envVars["GHU_FULLPATH"]}\":$PATH /bin/bash" + $"PATH=\"{envVars["GHU_FULLPATH"]}\" /bin/bash" }; environment.FileSystem.WriteAllLines(envVarFile, scriptContents); Mono.Unix.Native.Syscall.chmod(envVarFile, (Mono.Unix.Native.FilePermissions)493); // -rwxr-xr-x mode (0755) @@ -107,7 +107,7 @@ public void RunCommandLineWindow(NPath workingDirectory) else { startInfo.FileName = "sh"; - gitEnvironment.Configure(startInfo, workingDirectory, environment.IsCustomGitExecutable); + gitEnvironment.Configure(startInfo, workingDirectory); } Process.Start(startInfo); diff --git a/src/GitHub.Api/Platform/DefaultEnvironment.cs b/src/GitHub.Api/Platform/DefaultEnvironment.cs index ad385f75f..1fd414d0b 100644 --- a/src/GitHub.Api/Platform/DefaultEnvironment.cs +++ b/src/GitHub.Api/Platform/DefaultEnvironment.cs @@ -13,6 +13,7 @@ public class DefaultEnvironment : IEnvironment private static bool? onMac; private NPath gitExecutablePath; + private NPath gitLfsExecutablePath; private NPath nodeJsExecutablePath; private NPath octorunScriptPath; @@ -163,6 +164,17 @@ public NPath GitExecutablePath GitInstallPath = GitExecutablePath.Resolve().Parent.Parent; } } + + public NPath GitLfsExecutablePath + { + get { return gitLfsExecutablePath; } + set + { + gitLfsExecutablePath = value; + GitLfsInstallPath = gitLfsExecutablePath.IsInitialized ? gitLfsExecutablePath.Parent : NPath.Default; + } + } + public NPath NodeJsExecutablePath { get @@ -177,6 +189,7 @@ public NPath NodeJsExecutablePath } } public NPath GitInstallPath { get; private set; } + public NPath GitLfsInstallPath { get; private set; } public NPath RepositoryPath { get; private set; } public ICacheContainer CacheContainer { get; private set; } public IRepository Repository { get; set; } diff --git a/src/GitHub.Api/Platform/IEnvironment.cs b/src/GitHub.Api/Platform/IEnvironment.cs index 3be9a6ae4..f25161da7 100644 --- a/src/GitHub.Api/Platform/IEnvironment.cs +++ b/src/GitHub.Api/Platform/IEnvironment.cs @@ -35,5 +35,7 @@ public interface IEnvironment IRepository Repository { get; set; } string ExecutableExtension { get; } ICacheContainer CacheContainer { get; } + NPath GitLfsInstallPath { get; } + NPath GitLfsExecutablePath { get; set; } } } \ No newline at end of file diff --git a/src/GitHub.Api/Platform/ProcessEnvironment.cs b/src/GitHub.Api/Platform/ProcessEnvironment.cs index 0f58ba8fa..259d828b7 100644 --- a/src/GitHub.Api/Platform/ProcessEnvironment.cs +++ b/src/GitHub.Api/Platform/ProcessEnvironment.cs @@ -1,5 +1,6 @@ using GitHub.Logging; using System; +using System.Collections.Generic; using System.Diagnostics; namespace GitHub.Unity @@ -17,58 +18,86 @@ public ProcessEnvironment(IEnvironment environment) public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSetupGit = false) { - Guard.ArgumentNotNull(psi, "psi"); - psi.WorkingDirectory = workingDirectory; psi.EnvironmentVariables["HOME"] = NPath.HomeDirectory; psi.EnvironmentVariables["TMP"] = psi.EnvironmentVariables["TEMP"] = NPath.SystemTemp; + + var path = Environment.Path; psi.EnvironmentVariables["GHU_WORKINGDIR"] = workingDirectory; - psi.EnvironmentVariables["PATH"] = Environment.Path; - psi.EnvironmentVariables["GHU_FULLPATH"] = Environment.Path; - // if we don't know where git is, then there's nothing else to configure - if (!Environment.GitInstallPath.IsInitialized || dontSetupGit) + if (dontSetupGit) + { + psi.EnvironmentVariables["GHU_FULLPATH"] = path; + psi.EnvironmentVariables["PATH"] = path; return; - - var httpProxy = Environment.GetEnvironmentVariable("HTTP_PROXY"); - if (!String.IsNullOrEmpty(httpProxy)) - psi.EnvironmentVariables["HTTP_PROXY"] = httpProxy; - - var httpsProxy = Environment.GetEnvironmentVariable("HTTPS_PROXY"); - if (!String.IsNullOrEmpty(httpsProxy)) - psi.EnvironmentVariables["HTTPS_PROXY"] = httpsProxy; - - //TODO: Remove with Git LFS Locking becomes standard - psi.EnvironmentVariables["GITLFSLOCKSENABLED"] = "1"; + } + + Guard.ArgumentNotNull(psi, "psi"); + + var pathEntries = new List(); + string separator = Environment.IsWindows ? ";" : ":"; - if (Environment.IsWindows) + if (Environment.GitInstallPath.IsInitialized) { - // We need to essentially fake up what git-cmd.bat does var gitPathRoot = Environment.GitInstallPath; - + var gitExecutableDir = Environment.GitExecutablePath.Parent; // original path to git (might be different from install path if it's a symlink) + var baseExecPath = gitPathRoot; - if (baseExecPath.DirectoryExists("mingw32")) - baseExecPath = baseExecPath.Combine("mingw32"); - else - baseExecPath = baseExecPath.Combine("mingw64"); - var binPath = baseExecPath.Combine("bin"); - + var binPath = baseExecPath; + if (Environment.IsWindows) + { + if (baseExecPath.DirectoryExists("mingw32")) + baseExecPath = baseExecPath.Combine("mingw32"); + else + baseExecPath = baseExecPath.Combine("mingw64"); + binPath = baseExecPath.Combine("bin"); + } + var execPath = baseExecPath.Combine("libexec", "git-core"); if (!execPath.DirectoryExists()) execPath = NPath.Default; - var userPath = @"C:\windows\system32;C:\windows"; - var path = $"{gitPathRoot}\\cmd;{gitPathRoot}\\usr\\bin;{execPath};{binPath}"; - + if (Environment.IsWindows) + { + pathEntries.AddRange(new[] { gitPathRoot.Combine("cmd").ToString(), gitPathRoot.Combine("usr", "bin") }); + } + else + { + pathEntries.Add(gitExecutableDir.ToString()); + } + if (execPath.IsInitialized) + pathEntries.Add(execPath); + pathEntries.Add(binPath); + if (execPath.IsInitialized) psi.EnvironmentVariables["GIT_EXEC_PATH"] = execPath.ToString(); - - psi.EnvironmentVariables["PATH"] = path; - psi.EnvironmentVariables["GHU_FULLPATH"] = path; - - psi.EnvironmentVariables["PLINK_PROTOCOL"] = "ssh"; - psi.EnvironmentVariables["TERM"] = "msys"; } + + if (Environment.GitLfsInstallPath.IsInitialized && Environment.GitInstallPath != Environment.GitLfsInstallPath) + { + pathEntries.Add(Environment.GitLfsInstallPath); + } + + pathEntries.Add("END"); + + path = String.Join(separator, pathEntries.ToArray()) + separator + path; + + psi.EnvironmentVariables["GHU_FULLPATH"] = path; + psi.EnvironmentVariables["PATH"] = path; + + //TODO: Remove with Git LFS Locking becomes standard + psi.EnvironmentVariables["GITLFSLOCKSENABLED"] = "1"; + + psi.EnvironmentVariables["PLINK_PROTOCOL"] = "ssh"; + psi.EnvironmentVariables["TERM"] = "msys"; + + var httpProxy = Environment.GetEnvironmentVariable("HTTP_PROXY"); + if (!String.IsNullOrEmpty(httpProxy)) + psi.EnvironmentVariables["HTTP_PROXY"] = httpProxy; + + var httpsProxy = Environment.GetEnvironmentVariable("HTTPS_PROXY"); + if (!String.IsNullOrEmpty(httpsProxy)) + psi.EnvironmentVariables["HTTPS_PROXY"] = httpsProxy; } } } \ No newline at end of file diff --git a/src/GitHub.Api/Tasks/ProcessTask.cs b/src/GitHub.Api/Tasks/ProcessTask.cs index dccca3146..2debe995a 100644 --- a/src/GitHub.Api/Tasks/ProcessTask.cs +++ b/src/GitHub.Api/Tasks/ProcessTask.cs @@ -350,7 +350,7 @@ public override string ToString() public Process Process { get; set; } public int ProcessId { get { return Process.Id; } } - public override bool Successful { get { return Task.Status == TaskStatus.RanToCompletion && Process.ExitCode == 0; } } + public override bool Successful { get { return !taskFailed && Task.Status == TaskStatus.RanToCompletion && Process.ExitCode == 0; } } public StreamWriter StandardInput { get { return wrapper?.Input; } } public virtual string ProcessName { get; protected set; } public virtual string ProcessArguments { get; } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs index 213254e92..a68da21b4 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs @@ -142,6 +142,7 @@ public override void OnGUI() new FindExecTask("git", Manager.CancellationToken) .Configure(Manager.ProcessManager, false, true) + .Catch(ex => true) .FinallyInUI((success, ex, path) => { if (success) { @@ -242,7 +243,7 @@ private void ValidateAndSetGitInstallPath(string value) EntryPoint.ApplicationManager.TaskManager); gitInstaller.SetupGitIfNeeded() - .FinallyInUI((success, exception, result) => + .FinallyInUI((success, exception, installationState) => { Logger.Trace("Setup Git Using the installer:{0}", success); @@ -254,7 +255,8 @@ private void ValidateAndSetGitInstallPath(string value) else { Manager.SystemSettings.Unset(Constants.GitInstallPathKey); - Environment.GitExecutablePath = result; + Environment.GitExecutablePath = installationState.GitExecutablePath; + Environment.GitLfsExecutablePath = installationState.GitLfsExecutablePath; Environment.IsCustomGitExecutable = false; gitExecHasChanged = true; diff --git a/src/tests/IntegrationTests/BaseIntegrationTest.cs b/src/tests/IntegrationTests/BaseIntegrationTest.cs index d6fad1bc0..3df988898 100644 --- a/src/tests/IntegrationTests/BaseIntegrationTest.cs +++ b/src/tests/IntegrationTests/BaseIntegrationTest.cs @@ -80,11 +80,14 @@ protected void InitializeEnvironment(NPath repoPath, initializeRepository); } - private void InitializePlatform(NPath repoPath, NPath? environmentPath, bool enableEnvironmentTrace, - bool setupGit = true, string testName = "") + protected void InitializePlatform(NPath repoPath, NPath? environmentPath = null, + bool enableEnvironmentTrace = true, + bool setupGit = true, + string testName = "", + bool initializeRepository = true) { InitializeTaskManager(); - InitializeEnvironment(repoPath, environmentPath, enableEnvironmentTrace, true); + InitializeEnvironment(repoPath, environmentPath, enableEnvironmentTrace, initializeRepository); Platform = new Platform(Environment); ProcessManager = new ProcessManager(Environment, GitEnvironment, TaskManager.Token); @@ -141,7 +144,7 @@ protected void SetupGit(NPath pathToSetupGitInto, string testName) { var autoResetEvent = new AutoResetEvent(false); - var installDetails = new GitInstaller.GitInstallDetails(pathToSetupGitInto, true); + var installDetails = new GitInstaller.GitInstallDetails(pathToSetupGitInto, Environment.IsWindows); var zipArchivesPath = pathToSetupGitInto.Combine("downloads").CreateDirectory(); @@ -159,9 +162,9 @@ protected void SetupGit(NPath pathToSetupGitInto, string testName) var setupTask = gitInstaller.SetupGitIfNeeded(); setupTask.OnEnd += (thisTask, _, __, ___) => { - ((ITask)thisTask.GetEndOfChain()).OnEnd += (t, path, success, exception) => + ((ITask)thisTask.GetEndOfChain()).OnEnd += (t, state, success, exception) => { - result = path; + result = state.GitExecutablePath; ex = exception; autoResetEvent.Set(); }; diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 11719fc0a..ae20aba5d 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -21,8 +21,8 @@ public async Task DownloadAndVerificationWorks() ILogging logger; StartTest(out watch, out logger); - var fileUrl = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); - var md5Url = new UriString($"http://localhost:{server.Port}/git-lfs.zip.md5"); + var fileUrl = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip"); + var md5Url = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip.md5"); var downloader = new Downloader(); StartTrackTime(watch, logger, md5Url); @@ -45,7 +45,7 @@ public async Task DownloadingNonExistingFileThrows() StartTest(out watch, out logger); var fileUrl = new UriString($"http://localhost:{server.Port}/nope"); - var md5Url = new UriString($"http://localhost:{server.Port}/git-lfs.zip.md5"); + var md5Url = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip.md5"); var downloader = new Downloader(); StartTrackTime(watch, logger, md5Url); @@ -63,8 +63,8 @@ public async Task FailsIfVerificationFails() ILogging logger; StartTest(out watch, out logger); - var fileUrl = new UriString($"http://localhost:{server.Port}/git.zip"); - var md5Url = new UriString($"http://localhost:{server.Port}/git-lfs.zip.md5"); + var fileUrl = new UriString($"http://localhost:{server.Port}/git/windows/git.zip"); + var md5Url = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip.md5"); var downloader = new Downloader(); StartTrackTime(watch, logger, md5Url); @@ -83,8 +83,8 @@ public async Task ResumingWorks() StartTest(out watch, out logger); var fileSystem = NPath.FileSystem; - var fileUrl = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); - var md5Url = new UriString($"http://localhost:{server.Port}/git-lfs.zip.md5"); + var fileUrl = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip"); + var md5Url = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip.md5"); var downloader = new Downloader(); StartTrackTime(watch, logger, md5Url); @@ -124,8 +124,8 @@ public async Task SucceedIfEverythingIsAlreadyDownloaded() StartTest(out watch, out logger); var fileSystem = NPath.FileSystem; - var fileUrl = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); - var md5Url = new UriString($"http://localhost:{server.Port}/git-lfs.zip.md5"); + var fileUrl = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip"); + var md5Url = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip.md5"); var downloader = new Downloader(); StartTrackTime(watch, logger, md5Url); @@ -157,10 +157,10 @@ public async Task DownloadsRunSideBySide() ILogging logger; StartTest(out watch, out logger); - var fileUrl1 = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); - var md5Url1 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.md5"); - var fileUrl2 = new UriString($"http://localhost:{server.Port}/git.zip"); - var md5Url2 = new UriString($"http://localhost:{server.Port}/git.zip.md5"); + var fileUrl1 = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip"); + var md5Url1 = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip.md5"); + var fileUrl2 = new UriString($"http://localhost:{server.Port}/git/windows/git.zip"); + var md5Url2 = new UriString($"http://localhost:{server.Port}/git/windows/git.zip.md5"); var events = new List(); @@ -200,8 +200,8 @@ public async Task ResumingDownloadsWorks() var fileSystem = NPath.FileSystem; - var gitLfs = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); - var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.md5"); + var gitLfs = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip"); + var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip.md5"); var downloadTask = new DownloadTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath); @@ -290,7 +290,7 @@ public void DownloadingNonExistingFileThrows() // var fileSystem = NPath.FileSystem; - // var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.md5"); + // var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip.md5"); // var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath); @@ -348,8 +348,8 @@ public void DownloadingFromNonExistingDomainThrows() // var fileSystem = NPath.FileSystem; - // var gitLfs = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); - // var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.md5"); + // var gitLfs = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip"); + // var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip.md5"); // var downloadGitLfsMd5Task = new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath); // var downloadGitLfsTask = new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath); @@ -391,7 +391,7 @@ public void ShutdownTimeWhenTaskManagerDisposed() var evtFinally = new AutoResetEvent(false); Exception exception = null; - var gitLfs = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); + var gitLfs = new UriString($"http://localhost:{server.Port}/git/windows/git-lfs.zip"); StartTrackTime(watch, logger, gitLfs); var downloadGitTask = new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath) diff --git a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs index c77d55e98..e1f48f6a5 100644 --- a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs +++ b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs @@ -15,7 +15,7 @@ class GitInstallerTests : BaseIntegrationTest public override void OnSetup() { base.OnSetup(); - InitializeEnvironment(TestBasePath, initializeRepository: false); + InitializePlatform(TestBasePath, setupGit: false, initializeRepository: false); } private TestWebServer.HttpServer server; @@ -32,10 +32,11 @@ public override void TestFixtureTearDown() base.TestFixtureTearDown(); server.Stop(); ApplicationConfiguration.WebTimeout = ApplicationConfiguration.DefaultWebTimeout; + ZipHelper.Instance = null; } [Test] - public void GitInstallTest() + public void GitInstallWindows() { var gitInstallationPath = TestBasePath.Combine("GitInstall").CreateDirectory(); @@ -49,14 +50,84 @@ public void GitInstallTest() TestBasePath.Combine("git").CreateDirectory(); + var zipHelper = Substitute.For(); + zipHelper.Extract(Arg.Any(), Arg.Do(x => + { + var n = x.ToNPath(); + n.EnsureDirectoryExists(); + if (n.FileName == "git-lfs") + { + n.Combine("git-lfs" + Environment.ExecutableExtension).WriteAllText(""); + } + }), Arg.Any(), Arg.Any>()).Returns(true); + ZipHelper.Instance = zipHelper; + var gitInstaller = new GitInstaller(Environment, ProcessManager, TaskManager, installDetails); + var startTask = gitInstaller.SetupGitIfNeeded(); + var endTask = new FuncTask(TaskManager.Token, (s, state) => state); + startTask.OnEnd += (thisTask, path, success, exception) => thisTask.GetEndOfChain().Then(endTask); + startTask.Start(); + GitInstaller.GitInstallationState result = null; + Assert.DoesNotThrow(async () => result = await endTask.Task); + result.Should().NotBeNull(); + + Assert.AreEqual(gitInstallationPath.Combine(installDetails.PackageNameWithVersion), result.GitInstallationPath); + result.GitExecutablePath.Should().Be(gitInstallationPath.Combine(installDetails.PackageNameWithVersion, "cmd", "git" + Environment.ExecutableExtension)); + result.GitLfsExecutablePath.Should().Be(gitInstallationPath.Combine(installDetails.PackageNameWithVersion, "mingw32", "libexec", "git-core", "git-lfs" + Environment.ExecutableExtension)); + + var isCustomGitExec = result.GitExecutablePath != result.GitExecutablePath; + + Environment.GitExecutablePath = result.GitExecutablePath; + Environment.GitLfsExecutablePath = result.GitLfsExecutablePath; + + Environment.IsCustomGitExecutable = isCustomGitExec; + + var procTask = new SimpleProcessTask(TaskManager.Token, "something") + .Configure(ProcessManager); + procTask.Process.StartInfo.EnvironmentVariables["PATH"].Should().StartWith(gitInstallationPath.ToString()); + } + + //[Test] + public void GitInstallMac() + { + var filesystem = Substitute.For(); + DefaultEnvironment.OnMac = true; + DefaultEnvironment.OnWindows = false; + + var gitInstallationPath = TestBasePath.Combine("GitInstall").CreateDirectory(); + + var installDetails = new GitInstaller.GitInstallDetails(gitInstallationPath, Environment.IsWindows) + { + GitZipMd5Url = $"http://localhost:{server.Port}/{new Uri(GitInstaller.GitInstallDetails.DefaultGitZipMd5Url).AbsolutePath}", + GitZipUrl = $"http://localhost:{server.Port}/{new Uri(GitInstaller.GitInstallDetails.DefaultGitZipUrl).AbsolutePath}", + GitLfsZipMd5Url = $"http://localhost:{server.Port}/{new Uri(GitInstaller.GitInstallDetails.DefaultGitLfsZipMd5Url).AbsolutePath}", + GitLfsZipUrl = $"http://localhost:{server.Port}/{new Uri(GitInstaller.GitInstallDetails.DefaultGitLfsZipUrl).AbsolutePath}", + }; + + TestBasePath.Combine("git").CreateDirectory(); + var gitInstaller = new GitInstaller(Environment, ProcessManager, TaskManager, installDetails); var startTask = gitInstaller.SetupGitIfNeeded(); - var endTask = new FuncTask(TaskManager.Token, (s, path) => path); + var endTask = new FuncTask(TaskManager.Token, (s, state) => state); startTask.OnEnd += (thisTask, path, success, exception) => thisTask.GetEndOfChain().Then(endTask); startTask.Start(); - NPath? resultPath = null; - Assert.DoesNotThrow(async () => resultPath = await endTask.Task); - resultPath.Should().NotBeNull(); + GitInstaller.GitInstallationState result = null; + Assert.DoesNotThrow(async () => result = await endTask.Task); + result.Should().NotBeNull(); + + Assert.AreEqual(gitInstallationPath.Combine(installDetails.PackageNameWithVersion), result.GitInstallationPath); + result.GitExecutablePath.Should().Be(gitInstallationPath.Combine("bin", "git" + Environment.ExecutableExtension)); + result.GitLfsExecutablePath.Should().Be(gitInstallationPath.Combine(installDetails.PackageNameWithVersion, "libexec", "git-core", "git-lfs" + Environment.ExecutableExtension)); + + var isCustomGitExec = result.GitExecutablePath != result.GitExecutablePath; + + Environment.GitExecutablePath = result.GitExecutablePath; + Environment.GitLfsExecutablePath = result.GitLfsExecutablePath; + + Environment.IsCustomGitExecutable = isCustomGitExec; + + var procTask = new SimpleProcessTask(TaskManager.Token, "something") + .Configure(ProcessManager); + procTask.Process.StartInfo.EnvironmentVariables["PATH"].Should().StartWith(gitInstallationPath.ToString()); } } } \ No newline at end of file diff --git a/src/tests/IntegrationTests/IntegrationTestEnvironment.cs b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs index 36937d56f..06bc6f744 100644 --- a/src/tests/IntegrationTests/IntegrationTestEnvironment.cs +++ b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs @@ -129,6 +129,8 @@ public NPath GitExecutablePath public NPath RepositoryPath => defaultEnvironment.RepositoryPath; public NPath GitInstallPath => defaultEnvironment.GitInstallPath; + public NPath GitLfsInstallPath => defaultEnvironment.GitLfsInstallPath; + public NPath GitLfsExecutablePath { get { return defaultEnvironment.GitLfsExecutablePath; } set { defaultEnvironment.GitLfsExecutablePath = value; } } public IRepository Repository { get { return defaultEnvironment.Repository; } set { defaultEnvironment.Repository = value; } } public IUser User { get { return defaultEnvironment.User; } set { defaultEnvironment.User = value; } } diff --git a/src/tests/TestWebServer/TestWebServer.csproj b/src/tests/TestWebServer/TestWebServer.csproj index 82dd24397..54d84b98d 100644 --- a/src/tests/TestWebServer/TestWebServer.csproj +++ b/src/tests/TestWebServer/TestWebServer.csproj @@ -42,6 +42,40 @@ + + + files\git\windows\git.zip + PreserveNewest + + + files\git\windows\git.zip.md5 + PreserveNewest + + + files\git\windows\git-lfs.zip + PreserveNewest + + + files\git\windows\git-lfs.zip.md5 + PreserveNewest + + + + files\git\mac\git-lfs.zip + PreserveNewest + + + files\git\mac\git-lfs.zip.md5 + PreserveNewest + + {bb6a8eda-15d8-471b-a6ed-ee551e0b3ba0} From 0ab575914b37109ad02212f4aaf07fe2a020cfc9 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 4 Apr 2018 22:46:54 +0200 Subject: [PATCH 18/31] Fix repository manager tests. Also fix a bug detecting tracking branches --- src/GitHub.Api/Git/GitConfig.cs | 10 ++- src/GitHub.Api/Git/RepositoryManager.cs | 9 ++- .../Editor/GitHub.Unity/ApplicationCache.cs | 2 +- .../IntegrationTests/BaseIntegrationTest.cs | 7 ++ src/tests/IntegrationTests/CachingClasses.cs | 3 +- .../Events/RepositoryManagerTests.cs | 74 +++++++------------ 6 files changed, 50 insertions(+), 55 deletions(-) diff --git a/src/GitHub.Api/Git/GitConfig.cs b/src/GitHub.Api/Git/GitConfig.cs index dd0cc5f18..b2277295c 100644 --- a/src/GitHub.Api/Git/GitConfig.cs +++ b/src/GitHub.Api/Git/GitConfig.cs @@ -79,17 +79,20 @@ public struct ConfigBranch public string name; public ConfigRemote remote; + public string trackingBranch; public ConfigBranch(string name) { this.name = name; + this.trackingBranch = null; remote = ConfigRemote.Default; } - public ConfigBranch(string name, ConfigRemote? remote) + public ConfigBranch(string name, ConfigRemote? remote, string trackingBranch) { this.name = name; this.remote = remote ?? ConfigRemote.Default; + this.trackingBranch = trackingBranch != null && trackingBranch.StartsWith("refs/heads") ? trackingBranch.Substring("refs/heads".Length + 1) : null; } public override int GetHashCode() @@ -137,6 +140,7 @@ public bool Equals(ConfigBranch other) public bool IsTracking => Remote.HasValue; public string Name => name; + public string TrackingBranch => trackingBranch; public ConfigRemote? Remote => Equals(remote, ConfigRemote.Default) ? (ConfigRemote?) null : remote; @@ -189,7 +193,7 @@ public IEnumerable GetBranches() return groups .Where(x => x.Key == "branch") .SelectMany(x => x.Value) - .Select(x => new ConfigBranch(x.Key, GetRemote(x.Value.TryGetString("remote")))); + .Select(x => new ConfigBranch(x.Key, GetRemote(x.Value.TryGetString("remote")), x.Value.TryGetString("merge"))); } public IEnumerable GetRemotes() @@ -217,7 +221,7 @@ public IEnumerable GetRemotes() .Where(x => x.Key == "branch") .SelectMany(x => x.Value) .Where(x => x.Key == branch) - .Select(x => new ConfigBranch(x.Key,GetRemote(x.Value.TryGetString("remote"))) as ConfigBranch?) + .Select(x => new ConfigBranch(x.Key, GetRemote(x.Value.TryGetString("remote")), x.Value.TryGetString("merge")) as ConfigBranch?) .FirstOrDefault(); } diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index f9f53a83d..7cfd80562 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -348,7 +348,7 @@ public void UpdateGitAheadBehindStatus() if (configBranch.HasValue && configBranch.Value.Remote.HasValue) { var name = configBranch.Value.Name; - var trackingName = configBranch.Value.IsTracking ? configBranch.Value.Remote.Value.Name + "/" + name : "[None]"; + var trackingName = configBranch.Value.IsTracking ? configBranch.Value.Remote.Value.Name + "/" + configBranch.Value.TrackingBranch : "[None]"; var task = GitClient.AheadBehindStatus(name, trackingName) .Then((success, status) => @@ -491,6 +491,10 @@ private void WatcherOnLocalBranchesChanged() { Logger.Trace("WatcherOnLocalBranchesChanged"); DataNeedsRefreshing?.Invoke(CacheType.Branches); + // the watcher should tell us what branch has changed so we can fire this only + // when the active branch has changed + DataNeedsRefreshing?.Invoke(CacheType.GitLog); + DataNeedsRefreshing?.Invoke(CacheType.GitAheadBehind); } private void WatcherOnRepositoryCommitted() @@ -520,6 +524,7 @@ private void WatcherOnHeadChanged() Logger.Trace("WatcherOnHeadChanged"); DataNeedsRefreshing?.Invoke(CacheType.RepositoryInfo); DataNeedsRefreshing?.Invoke(CacheType.GitLog); + DataNeedsRefreshing?.Invoke(CacheType.GitAheadBehind); } private void WatcherOnIndexChanged() @@ -577,7 +582,7 @@ private void UpdateRemoteBranches() .Select(x => x.RelativeTo(basedir)) .Select(x => x.ToString(SlashMode.Forward))) { - branchList.Add(branch, new ConfigBranch(branch, remotes[remote])); + branchList.Add(branch, new ConfigBranch(branch, remotes[remote], null)); } remoteBranches.Add(remote, branchList); diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs index 794f9ef8b..a1cefc458 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs @@ -590,7 +590,7 @@ public void AddRemoteBranch(string remote, string branch) if (!branchList.ContainsKey(branch)) { var now = DateTimeOffset.Now; - branchList.Add(branch, new ConfigBranch(branch, ConfigRemotes[remote])); + branchList.Add(branch, new ConfigBranch(branch, ConfigRemotes[remote], null)); Logger.Trace("AddRemoteBranch {0} remote:{1} branch:{2} ", now, remote, branch); SaveData(now, true); } diff --git a/src/tests/IntegrationTests/BaseIntegrationTest.cs b/src/tests/IntegrationTests/BaseIntegrationTest.cs index d6fad1bc0..de1de8260 100644 --- a/src/tests/IntegrationTests/BaseIntegrationTest.cs +++ b/src/tests/IntegrationTests/BaseIntegrationTest.cs @@ -216,6 +216,13 @@ public virtual void OnTearDown() { TaskManager.Dispose(); Environment?.CacheContainer.Dispose(); + BranchesCache.Instance = null; + GitAheadBehindCache.Instance = null; + GitLocksCache.Instance = null; + GitLogCache.Instance = null; + GitStatusCache.Instance = null; + GitUserCache.Instance = null; + RepositoryInfoCache.Instance = null; Logger.Debug("Deleting TestBasePath: {0}", TestBasePath.ToString()); for (var i = 0; i < 5; i++) diff --git a/src/tests/IntegrationTests/CachingClasses.cs b/src/tests/IntegrationTests/CachingClasses.cs index 685a21cd9..bdf462151 100644 --- a/src/tests/IntegrationTests/CachingClasses.cs +++ b/src/tests/IntegrationTests/CachingClasses.cs @@ -19,6 +19,7 @@ public static T Instance CreateAndLoad(); return instance; } + set { instance = value; } } protected ScriptObjectSingleton() @@ -560,7 +561,7 @@ public void AddRemoteBranch(string remote, string branch) if (!branchList.ContainsKey(branch)) { var now = DateTimeOffset.Now; - branchList.Add(branch, new ConfigBranch(branch, ConfigRemotes[remote])); + branchList.Add(branch, new ConfigBranch(branch, ConfigRemotes[remote], null)); Logger.Trace("AddRemoteBranch {0} remote:{1} branch:{2} ", now, remote, branch); SaveData(now, true); } diff --git a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs index a7a4a0c22..315fb3483 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -18,7 +18,7 @@ namespace IntegrationTests class RepositoryManagerTests : BaseGitEnvironmentTest { private RepositoryManagerEvents repositoryManagerEvents; - private TimeSpan Timeout = TimeSpan.FromSeconds(5); + private TimeSpan Timeout = TimeSpan.FromMilliseconds(800); public override void OnSetup() { @@ -97,7 +97,7 @@ public async Task ShouldDetectFileChanges() repositoryManagerEvents.WaitForNotBusy(); StopTrackTimeAndLog(watch, logger); - repositoryManagerEvents.GitStatusUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -143,7 +143,7 @@ public async Task ShouldAddAndCommitFiles() RepositoryManager.WaitForEvents(); repositoryManagerEvents.WaitForNotBusy(); - repositoryManagerEvents.GitStatusUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -165,9 +165,7 @@ await RepositoryManager RepositoryManager.WaitForEvents(); repositoryManagerEvents.WaitForNotBusy(); - repositoryManagerEvents.LocalBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitStatusUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitLogUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -218,7 +216,7 @@ public async Task ShouldAddAndCommitAllFiles() repositoryManagerEvents.WaitForNotBusy(); StopTrackTimeAndLog(watch, logger); - repositoryManagerEvents.GitStatusUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -248,11 +246,8 @@ await RepositoryManager repositoryManagerEvents.WaitForNotBusy(); StopTrackTimeAndLog(watch, logger); - repositoryManagerEvents.GitStatusUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.LocalBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitLogUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); @@ -291,9 +286,7 @@ public async Task ShouldDetectBranchChange() RepositoryManager.WaitForEvents(); repositoryManagerEvents.WaitForNotBusy(); - repositoryManagerEvents.CurrentBranchUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitStatusUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitLogUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -334,11 +327,7 @@ public async Task ShouldDetectBranchDelete() RepositoryManager.WaitForEvents(); repositoryManagerEvents.WaitForNotBusy(); - repositoryManagerEvents.CurrentBranchUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.LocalBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.RemoteBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitAheadBehindStatusUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitLogUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -380,14 +369,15 @@ public async Task ShouldDetectBranchCreate() RepositoryManager.WaitForEvents(); repositoryManagerEvents.WaitForNotBusy(); - repositoryManagerEvents.LocalBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.DidNotReceive().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); + repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); - repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); + // TODO: log should not be getting called, but it is because when branches get changed we're blindly calling log + //repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); @@ -403,14 +393,15 @@ public async Task ShouldDetectBranchCreate() repositoryManagerEvents.WaitForNotBusy(); - repositoryManagerEvents.LocalBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); - repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); + // TODO: log should not be getting called, but it is because when branches get changed we're blindly calling log + //repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); } @@ -444,11 +435,7 @@ public async Task ShouldDetectChangesToRemotes() RepositoryManager.WaitForEvents(); repositoryManagerEvents.WaitForNotBusy(); - repositoryManagerEvents.CurrentBranchUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.RemoteBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.LocalBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitLogUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitAheadBehindStatusUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -468,11 +455,7 @@ public async Task ShouldDetectChangesToRemotes() RepositoryManager.WaitForEvents(); repositoryManagerEvents.WaitForNotBusy(); - repositoryManagerEvents.CurrentBranchUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.RemoteBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.LocalBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitLogUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitAheadBehindStatusUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -514,11 +497,7 @@ await RepositoryManager.CreateBranch("branch2", "another/master") RepositoryManager.WaitForEvents(); repositoryManagerEvents.WaitForNotBusy(); - repositoryManagerEvents.CurrentBranchUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.LocalBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.RemoteBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitAheadBehindStatusUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitLogUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -539,13 +518,12 @@ await RepositoryManager.SwitchBranch("branch2") RepositoryManager.WaitForEvents(); repositoryManagerEvents.WaitForNotBusy(); - repositoryManagerEvents.CurrentBranchUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitLogUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); + repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); repositoryManagerListener.DidNotReceive().LocalBranchesUpdated(Args.LocalBranchDictionary); @@ -581,8 +559,7 @@ public async Task ShouldDetectGitPull() RepositoryManager.WaitForEvents(); repositoryManagerEvents.WaitForNotBusy(); - repositoryManagerEvents.LocalBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitStatusUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -591,7 +568,8 @@ public async Task ShouldDetectGitPull() repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.DidNotReceive().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // TODO: this should not happen but it's happening right now because when local branches get updated in the cache, remotes get updated too + //repositoryManagerListener.DidNotReceive().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); } finally { @@ -623,15 +601,15 @@ public async Task ShouldDetectGitFetch() RepositoryManager.WaitForEvents(); repositoryManagerEvents.WaitForNotBusy(); - repositoryManagerEvents.RemoteBranchesUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitAheadBehindStatusUpdated.WaitOne(Timeout).Should().BeTrue(); + await TaskEx.Delay(Timeout); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); - repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); + // TODO: log should not be getting called, but it is because when branches get changed we're blindly calling log + //repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); } From cb9a0372fcebfbcacdb7f31e1fc3bcadb9df0211 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 4 Apr 2018 22:49:23 +0200 Subject: [PATCH 19/31] Maybe these are happy in appveyor now? --- src/tests/IntegrationTests/Events/RepositoryManagerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs index 315fb3483..50b494776 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -14,7 +14,7 @@ namespace IntegrationTests { - [TestFixture, Category("DoNotRunOnAppVeyor")] + [TestFixture /*, Category("DoNotRunOnAppVeyor") */] class RepositoryManagerTests : BaseGitEnvironmentTest { private RepositoryManagerEvents repositoryManagerEvents; From f7bdc687fcbbe29750f59a3447f1847e2fc0de93 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 4 Apr 2018 23:15:57 +0200 Subject: [PATCH 20/31] Maybe upping the timeout a bit will do? --- src/tests/IntegrationTests/Events/RepositoryManagerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs index 50b494776..f2613fe38 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -18,7 +18,7 @@ namespace IntegrationTests class RepositoryManagerTests : BaseGitEnvironmentTest { private RepositoryManagerEvents repositoryManagerEvents; - private TimeSpan Timeout = TimeSpan.FromMilliseconds(800); + private TimeSpan Timeout = TimeSpan.FromMilliseconds(1200); public override void OnSetup() { From 3b76bf2e35ca9ece524438916178635f0c2730cd Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 5 Apr 2018 15:25:25 +0200 Subject: [PATCH 21/31] Reduce trace noise --- src/GitHub.Api/Cache/CacheContainer.cs | 2 -- src/GitHub.Api/Git/Repository.cs | 1 - 2 files changed, 3 deletions(-) diff --git a/src/GitHub.Api/Cache/CacheContainer.cs b/src/GitHub.Api/Cache/CacheContainer.cs index aa4266b5f..f8de8c283 100644 --- a/src/GitHub.Api/Cache/CacheContainer.cs +++ b/src/GitHub.Api/Cache/CacheContainer.cs @@ -60,13 +60,11 @@ public void CheckAndRaiseEventsIfCacheNewer(CacheType cacheType, CacheUpdateEven private void OnCacheUpdated(CacheType cacheType, DateTimeOffset datetime) { - Logger.Trace("OnCacheUpdated cacheType:{0} datetime:{1}", cacheType, datetime); CacheUpdated.SafeInvoke(cacheType, datetime); } private void OnCacheInvalidated(CacheType cacheType) { - Logger.Trace("OnCacheInvalidated cacheType:{0}", cacheType); CacheInvalidated.SafeInvoke(cacheType); } diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 6e87c0e9a..293c377d4 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -176,7 +176,6 @@ private void CacheHasBeenInvalidated(CacheType cacheType) return; } - Logger.Trace($"CacheInvalidated {cacheType.ToString()}"); switch (cacheType) { case CacheType.Branches: From 537df2c21a660df99cde95cb77bf9d7e3fe8fa21 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 5 Apr 2018 15:26:18 +0200 Subject: [PATCH 22/31] Improve cache trace messages --- .../Editor/GitHub.Unity/ApplicationCache.cs | 21 +++++++++---------- src/tests/IntegrationTests/CachingClasses.cs | 20 +++++++++--------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs index a1cefc458..0bd338885 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs @@ -488,7 +488,7 @@ public GitBranch[] LocalBranches var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} localBranches:{1}", now, value); + Logger.Trace("{0} Updating LocalBranches: current:{1} new:{2}", now, localBranches, value); var localBranchesIsNull = localBranches == null; var valueIsNull = value == null; @@ -512,7 +512,7 @@ public GitBranch[] RemoteBranches var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} remoteBranches:{1}", now, value); + Logger.Trace("{0} Updating RemoteBranches: current:{1} new:{2}", now, remoteBranches, value); var remoteBranchesIsNull = remoteBranches == null; var valueIsNull = value == null; @@ -536,7 +536,7 @@ public GitRemote[] Remotes var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} remotes:{1}", now, value); + Logger.Trace("{0} Updating Remotes: current:{1} new:{2}", now, remotes, value); var remotesIsNull = remotes == null; var valueIsNull = value == null; @@ -671,7 +671,7 @@ public List Log var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} gitLog:{1}", now, value); + Logger.Trace("{0} Updating Log: current:{1} new:{2}", now, log.Count, value.Count); if (!log.SequenceEqual(value)) { @@ -707,8 +707,7 @@ public int Ahead var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} ahead:{1}", now, value); - + Logger.Trace("{0} Updating Ahead: current:{1} new:{2}", now, ahead, value); if (ahead != value) { ahead = value; @@ -731,7 +730,7 @@ public int Behind var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} behind:{1}", now, value); + Logger.Trace("{0} Updating Behind: current:{1} new:{2}", now, behind, value); if (behind != value) { @@ -766,7 +765,7 @@ public List Entries var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} entries:{1}", now, value.Count); + Logger.Trace("{0} Updating Entries: current:{1} new:{2}", now, entries.Count, value.Count); if (!entries.SequenceEqual(value)) { @@ -801,7 +800,7 @@ public List GitLocks var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} gitLocks:{1}", now, value); + Logger.Trace("{0} Updating GitLocks: current:{1} new:{2}", now, gitLocks.Count, value.Count); if (!gitLocks.SequenceEqual(value)) { @@ -837,7 +836,7 @@ public string Name var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} Name:{1}", now, value); + Logger.Trace("{0} Updating Name: current:{1} new:{2}", now, gitName, value); if (gitName != value) { @@ -861,7 +860,7 @@ public string Email var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} Email:{1}", now, value); + Logger.Trace("{0} Updating Email: current:{1} new:{2}", now, gitEmail, value); if (gitEmail != value) { diff --git a/src/tests/IntegrationTests/CachingClasses.cs b/src/tests/IntegrationTests/CachingClasses.cs index bdf462151..6b32cbaf4 100644 --- a/src/tests/IntegrationTests/CachingClasses.cs +++ b/src/tests/IntegrationTests/CachingClasses.cs @@ -459,7 +459,7 @@ public GitBranch[] LocalBranches var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} localBranches:{1}", now, value); + Logger.Trace("{0} Updating LocalBranches: current:{1} new:{2}", now, localBranches, value); var localBranchesIsNull = localBranches == null; var valueIsNull = value == null; @@ -483,7 +483,7 @@ public GitBranch[] RemoteBranches var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} remoteBranches:{1}", now, value); + Logger.Trace("{0} Updating RemoteBranches: current:{1} new:{2}", now, remoteBranches, value); var remoteBranchesIsNull = remoteBranches == null; var valueIsNull = value == null; @@ -507,7 +507,7 @@ public GitRemote[] Remotes var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} remotes:{1}", now, value); + Logger.Trace("{0} Updating Remotes: current:{1} new:{2}", now, remotes, value); var remotesIsNull = remotes == null; var valueIsNull = value == null; @@ -641,7 +641,7 @@ public List Log var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} gitLog:{1}", now, value); + Logger.Trace("{0} Updating Log: current:{1} new:{2}", now, log.Count, value.Count); if (!log.SequenceEqual(value)) { @@ -676,7 +676,7 @@ public int Ahead var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} ahead:{1}", now, value); + Logger.Trace("{0} Updating Ahead: current:{1} new:{2}", now, ahead, value); if (ahead != value) { @@ -700,7 +700,7 @@ public int Behind var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} behind:{1}", now, value); + Logger.Trace("{0} Updating Behind: current:{1} new:{2}", now, behind, value); if (behind != value) { @@ -734,7 +734,7 @@ public List Entries var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} entries:{1}", now, value.Count); + Logger.Trace("{0} Updating Entries: current:{1} new:{2}", now, entries.Count, value.Count); if (!entries.SequenceEqual(value)) { @@ -768,7 +768,7 @@ public List GitLocks var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} gitLocks:{1}", now, value); + Logger.Trace("{0} Updating GitLocks: current:{1} new:{2}", now, gitLocks.Count, value.Count); if (!gitLocks.SequenceEqual(value)) { @@ -803,7 +803,7 @@ public string Name var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} Name:{1}", now, value); + Logger.Trace("{0} Updating Name: current:{1} new:{2}", now, gitName, value); if (gitName != value) { @@ -827,7 +827,7 @@ public string Email var now = DateTimeOffset.Now; var isUpdated = false; - Logger.Trace("Updating: {0} Email:{1}", now, value); + Logger.Trace("{0} Updating Email: current:{1} new:{2}", now, gitEmail, value); if (gitEmail != value) { From 99f83c66fc3a3c38834fc244e0f465de8d51e29b Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 5 Apr 2018 15:26:53 +0200 Subject: [PATCH 23/31] Fix CA warnings --- src/GitHub.Api/Git/IRepository.cs | 2 +- src/GitHub.Api/Git/Repository.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/GitHub.Api/Git/IRepository.cs b/src/GitHub.Api/Git/IRepository.cs index 981aa5059..56db158fd 100644 --- a/src/GitHub.Api/Git/IRepository.cs +++ b/src/GitHub.Api/Git/IRepository.cs @@ -8,7 +8,7 @@ namespace GitHub.Unity /// public interface IRepository : IEquatable, IDisposable { - void Initialize(IRepositoryManager repositoryManager, ITaskManager taskManager); + void Initialize(IRepositoryManager theRepositoryManager, ITaskManager theTaskManager); void Start(); ITask CommitAllFiles(string message, string body); diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 293c377d4..dfa8db0ab 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -70,14 +70,14 @@ public Repository(NPath localPath, ICacheContainer container) }; } - public void Initialize(IRepositoryManager repositoryManager, ITaskManager taskManager) + public void Initialize(IRepositoryManager theRepositoryManager, ITaskManager theTaskManager) { //Logger.Trace("Initialize"); - Guard.ArgumentNotNull(repositoryManager, nameof(repositoryManager)); - Guard.ArgumentNotNull(taskManager, nameof(taskManager)); + Guard.ArgumentNotNull(theRepositoryManager, nameof(theRepositoryManager)); + Guard.ArgumentNotNull(theTaskManager, nameof(theTaskManager)); - this.taskManager = taskManager; - this.repositoryManager = repositoryManager; + this.taskManager = theTaskManager; + this.repositoryManager = theRepositoryManager; this.repositoryManager.CurrentBranchUpdated += RepositoryManagerOnCurrentBranchUpdated; this.repositoryManager.GitStatusUpdated += RepositoryManagerOnGitStatusUpdated; this.repositoryManager.GitAheadBehindStatusUpdated += RepositoryManagerOnGitAheadBehindStatusUpdated; From 11ffd11f8ab3ce111e4e420733186a502552e610 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 5 Apr 2018 15:27:17 +0200 Subject: [PATCH 24/31] Move to an async model in tests so we don't block the main thread --- .../Events/RepositoryManagerTests.cs | 175 ++++++++++++------ .../Events/IRepositoryManagerListener.cs | 76 +++++--- src/tests/TestUtils/TestUtils.csproj | 4 + src/tests/TestUtils/packages.config | 1 + 4 files changed, 165 insertions(+), 91 deletions(-) diff --git a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs index f2613fe38..b66f55005 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -80,8 +80,6 @@ public async Task ShouldDetectFileChanges() repositoryManagerListener.AttachListener(manager, repositoryManagerEvents); }); - //repositoryManagerListener.ClearReceivedCalls(); - //repositoryManagerEvents.Reset(); repositoryManagerListener.AssertDidNotReceiveAnyCalls(); var foobarTxt = TestRepoMasterCleanSynchronized.Combine("foobar.txt"); @@ -94,10 +92,10 @@ public async Task ShouldDetectFileChanges() StopTrackTimeAndLog(watch, logger); StartTrackTime(watch, logger, "repositoryManagerEvents.WaitForNotBusy()"); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); StopTrackTimeAndLog(watch, logger); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -141,9 +139,9 @@ public async Task ShouldAddAndCommitFiles() await TaskManager.Wait(); RepositoryManager.WaitForEvents(); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -157,15 +155,22 @@ public async Task ShouldAddAndCommitFiles() repositoryManagerListener.ClearReceivedCalls(); repositoryManagerEvents.Reset(); - await RepositoryManager - .CommitFiles(new List { "Assets\\TestDocument.txt", "foobar.txt" }, "IntegrationTest Commit", string.Empty) - .StartAsAsync(); + var filesToCommit = new List { "Assets\\TestDocument.txt", "foobar.txt" }; + var commitMessage = "IntegrationTest Commit"; + var commitBody = string.Empty; + + StartTrackTime(watch, logger, "CommitFiles"); + await RepositoryManager.CommitFiles(filesToCommit, commitMessage, commitBody).StartAsAsync(); + StopTrackTimeAndLog(watch, logger); await TaskManager.Wait(); RepositoryManager.WaitForEvents(); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); @@ -200,6 +205,8 @@ public async Task ShouldAddAndCommitAllFiles() repositoryManagerListener.AssertDidNotReceiveAnyCalls(); + logger.Trace("Add files"); + var foobarTxt = TestRepoMasterCleanSynchronized.Combine("foobar.txt"); foobarTxt.WriteAllText("foobar"); @@ -213,15 +220,16 @@ public async Task ShouldAddAndCommitAllFiles() StopTrackTimeAndLog(watch, logger); StartTrackTime(watch, logger, "repositoryManagerEvents.WaitForNotBusy()"); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); StopTrackTimeAndLog(watch, logger); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); + repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); + repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.DidNotReceive().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); repositoryManagerListener.DidNotReceive().LocalBranchesUpdated(Args.LocalBranchDictionary); @@ -231,9 +239,7 @@ public async Task ShouldAddAndCommitAllFiles() repositoryManagerEvents.Reset(); StartTrackTime(watch, logger, "CommitAllFiles"); - await RepositoryManager - .CommitAllFiles("IntegrationTest Commit", string.Empty) - .StartAsAsync(); + await RepositoryManager.CommitAllFiles("IntegrationTest Commit", string.Empty).StartAsAsync(); StopTrackTimeAndLog(watch, logger); await TaskManager.Wait(); @@ -243,10 +249,13 @@ await RepositoryManager StopTrackTimeAndLog(watch, logger); StartTrackTime(watch, logger, "repositoryManagerEvents.WaitForNotBusy()"); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); StopTrackTimeAndLog(watch, logger); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); @@ -284,16 +293,20 @@ public async Task ShouldDetectBranchChange() await TaskManager.Wait(); RepositoryManager.WaitForEvents(); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.DidNotReceive().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); + + repositoryManagerListener.DidNotReceive().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); + repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); repositoryManagerListener.DidNotReceive().LocalBranchesUpdated(Args.LocalBranchDictionary); repositoryManagerListener.DidNotReceive().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); } @@ -325,18 +338,25 @@ public async Task ShouldDetectBranchDelete() await TaskManager.Wait(); RepositoryManager.WaitForEvents(); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + + repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); + repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); } finally { @@ -367,19 +387,23 @@ public async Task ShouldDetectBranchCreate() await TaskManager.Wait(); RepositoryManager.WaitForEvents(); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); + repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); + repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); // TODO: log should not be getting called, but it is because when branches get changed we're blindly calling log //repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); repositoryManagerListener.ClearReceivedCalls(); repositoryManagerEvents.Reset(); @@ -391,19 +415,22 @@ public async Task ShouldDetectBranchCreate() RepositoryManager.WaitForEvents(); StopTrackTimeAndLog(watch, logger); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); + repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); + repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + + repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); // TODO: log should not be getting called, but it is because when branches get changed we're blindly calling log //repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); } finally { @@ -433,19 +460,24 @@ public async Task ShouldDetectChangesToRemotes() await TaskManager.Wait(); RepositoryManager.WaitForEvents(); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); + repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); + repositoryManagerListener.ClearReceivedCalls(); repositoryManagerEvents.Reset(); @@ -453,18 +485,23 @@ public async Task ShouldDetectChangesToRemotes() await TaskManager.Wait(); RepositoryManager.WaitForEvents(); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + + repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); + repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); } finally { @@ -490,42 +527,49 @@ public async Task ShouldDetectChangesToRemotesWhenSwitchingBranches() repositoryManagerListener.AssertDidNotReceiveAnyCalls(); - await RepositoryManager.CreateBranch("branch2", "another/master") - .StartAsAsync(); + await RepositoryManager.CreateBranch("branch2", "another/master").StartAsAsync(); await TaskManager.Wait(); RepositoryManager.WaitForEvents(); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); + repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); + repositoryManagerListener.ClearReceivedCalls(); repositoryManagerEvents.Reset(); - await RepositoryManager.SwitchBranch("branch2") - .StartAsAsync(); + await RepositoryManager.SwitchBranch("branch2").StartAsAsync(); await TaskManager.Wait(); RepositoryManager.WaitForEvents(); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); + + repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); repositoryManagerListener.DidNotReceive().LocalBranchesUpdated(Args.LocalBranchDictionary); repositoryManagerListener.DidNotReceive().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); } @@ -557,17 +601,22 @@ public async Task ShouldDetectGitPull() await TaskManager.Wait(); RepositoryManager.WaitForEvents(); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); + + repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); // TODO: this should not happen but it's happening right now because when local branches get updated in the cache, remotes get updated too //repositoryManagerListener.DidNotReceive().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); } @@ -599,19 +648,23 @@ public async Task ShouldDetectGitFetch() await TaskManager.Wait(); RepositoryManager.WaitForEvents(); - repositoryManagerEvents.WaitForNotBusy(); + await repositoryManagerEvents.WaitForNotBusy(); - await TaskEx.Delay(Timeout); + (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); + repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); + repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); // TODO: log should not be getting called, but it is because when branches get changed we're blindly calling log //repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); } finally { diff --git a/src/tests/TestUtils/Events/IRepositoryManagerListener.cs b/src/tests/TestUtils/Events/IRepositoryManagerListener.cs index ec0c4ddce..ad953b643 100644 --- a/src/tests/TestUtils/Events/IRepositoryManagerListener.cs +++ b/src/tests/TestUtils/Events/IRepositoryManagerListener.cs @@ -6,6 +6,7 @@ using NSubstitute; using GitHub.Logging; using NUnit.Framework; +using System.Threading.Tasks; namespace TestUtils.Events { @@ -23,33 +24,48 @@ interface IRepositoryManagerListener class RepositoryManagerEvents { - public EventWaitHandle IsBusy { get; } = new AutoResetEvent(false); - public EventWaitHandle IsNotBusy { get; } = new AutoResetEvent(false); - public EventWaitHandle CurrentBranchUpdated { get; } = new AutoResetEvent(false); - public EventWaitHandle GitAheadBehindStatusUpdated { get; } = new AutoResetEvent(false); - public EventWaitHandle GitStatusUpdated { get; } = new AutoResetEvent(false); - public EventWaitHandle GitLocksUpdated { get; } = new AutoResetEvent(false); - public EventWaitHandle GitLogUpdated { get; } = new AutoResetEvent(false); - public EventWaitHandle LocalBranchesUpdated { get; } = new AutoResetEvent(false); - public EventWaitHandle RemoteBranchesUpdated { get; } = new AutoResetEvent(false); + internal TaskCompletionSource isBusy; + public Task IsBusy => isBusy.Task; + internal TaskCompletionSource isNotBusy; + public Task IsNotBusy => isNotBusy.Task; + internal TaskCompletionSource currentBranchUpdated; + public Task CurrentBranchUpdated => currentBranchUpdated.Task; + internal TaskCompletionSource gitAheadBehindStatusUpdated; + public Task GitAheadBehindStatusUpdated => gitAheadBehindStatusUpdated.Task; + internal TaskCompletionSource gitStatusUpdated; + public Task GitStatusUpdated => gitStatusUpdated.Task; + internal TaskCompletionSource gitLocksUpdated; + public Task GitLocksUpdated => gitLocksUpdated.Task; + internal TaskCompletionSource gitLogUpdated; + public Task GitLogUpdated => gitLogUpdated.Task; + internal TaskCompletionSource localBranchesUpdated; + public Task LocalBranchesUpdated => localBranchesUpdated.Task; + internal TaskCompletionSource remoteBranchesUpdated; + public Task RemoteBranchesUpdated => remoteBranchesUpdated.Task; + + + public RepositoryManagerEvents() + { + Reset(); + } public void Reset() { - IsBusy.Reset(); - IsNotBusy.Reset(); - CurrentBranchUpdated.Reset(); - GitAheadBehindStatusUpdated.Reset(); - GitStatusUpdated.Reset(); - GitLocksUpdated.Reset(); - GitLogUpdated.Reset(); - LocalBranchesUpdated.Reset(); - RemoteBranchesUpdated.Reset(); + isBusy = new TaskCompletionSource(); + isNotBusy = new TaskCompletionSource(); + currentBranchUpdated = new TaskCompletionSource(); + gitAheadBehindStatusUpdated = new TaskCompletionSource(); + gitStatusUpdated = new TaskCompletionSource(); + gitLocksUpdated = new TaskCompletionSource(); + gitLogUpdated = new TaskCompletionSource(); + localBranchesUpdated = new TaskCompletionSource(); + remoteBranchesUpdated = new TaskCompletionSource(); } - public void WaitForNotBusy(int seconds = 1) + public async Task WaitForNotBusy(int seconds = 1) { - IsBusy.WaitOne(TimeSpan.FromSeconds(seconds)); - IsNotBusy.WaitOne(TimeSpan.FromSeconds(seconds)); + await TaskEx.WhenAny(IsBusy, TaskEx.Delay(TimeSpan.FromSeconds(seconds))); + await TaskEx.WhenAny(IsNotBusy, TaskEx.Delay(TimeSpan.FromSeconds(seconds))); } } @@ -64,51 +80,51 @@ public static void AttachListener(this IRepositoryManagerListener listener, logger?.Trace("OnIsBusyChanged: {0}", isBusy); listener.OnIsBusyChanged(isBusy); if (isBusy) - managerEvents?.IsBusy.Set(); + managerEvents?.isBusy.TrySetResult(true); else - managerEvents?.IsNotBusy.Set(); + managerEvents?.isNotBusy.TrySetResult(true); }; repositoryManager.CurrentBranchUpdated += (configBranch, configRemote) => { logger?.Trace("CurrentBranchUpdated"); listener.CurrentBranchUpdated(configBranch, configRemote); - managerEvents?.CurrentBranchUpdated.Set(); + managerEvents?.currentBranchUpdated.TrySetResult(true); }; repositoryManager.GitLocksUpdated += gitLocks => { logger?.Trace("GitLocksUpdated"); listener.GitLocksUpdated(gitLocks); - managerEvents?.GitLocksUpdated.Set(); + managerEvents?.gitLocksUpdated.TrySetResult(true); }; repositoryManager.GitAheadBehindStatusUpdated += gitAheadBehindStatus => { logger?.Trace("GitAheadBehindStatusUpdated"); listener.GitAheadBehindStatusUpdated(gitAheadBehindStatus); - managerEvents?.GitAheadBehindStatusUpdated.Set(); + managerEvents?.gitAheadBehindStatusUpdated.TrySetResult(true); }; repositoryManager.GitStatusUpdated += gitStatus => { logger?.Trace("GitStatusUpdated"); listener.GitStatusUpdated(gitStatus); - managerEvents?.GitStatusUpdated.Set(); + managerEvents?.gitStatusUpdated.TrySetResult(true); }; repositoryManager.GitLogUpdated += gitLogEntries => { logger?.Trace("GitLogUpdated"); listener.GitLogUpdated(gitLogEntries); - managerEvents?.GitLogUpdated.Set(); + managerEvents?.gitLogUpdated.TrySetResult(true); }; repositoryManager.LocalBranchesUpdated += branchList => { logger?.Trace("LocalBranchesUpdated"); listener.LocalBranchesUpdated(branchList); - managerEvents?.LocalBranchesUpdated.Set(); + managerEvents?.localBranchesUpdated.TrySetResult(true); }; repositoryManager.RemoteBranchesUpdated += (remotesList, branchList) => { logger?.Trace("RemoteBranchesUpdated"); listener.RemoteBranchesUpdated(remotesList, branchList); - managerEvents?.RemoteBranchesUpdated.Set(); + managerEvents?.remoteBranchesUpdated.TrySetResult(true); }; } diff --git a/src/tests/TestUtils/TestUtils.csproj b/src/tests/TestUtils/TestUtils.csproj index 4dad1fe33..8ae36c41d 100644 --- a/src/tests/TestUtils/TestUtils.csproj +++ b/src/tests/TestUtils/TestUtils.csproj @@ -30,6 +30,10 @@ 4 + + ..\..\..\packages\AsyncBridge.Net35.0.2.3333.0\lib\net35-Client\AsyncBridge.Net35.dll + True + $(SolutionDir)packages\FluentAssertions.2.2.0.0\lib\net35\FluentAssertions.dll True diff --git a/src/tests/TestUtils/packages.config b/src/tests/TestUtils/packages.config index f785ed1a6..3c80d2337 100644 --- a/src/tests/TestUtils/packages.config +++ b/src/tests/TestUtils/packages.config @@ -1,5 +1,6 @@  + From 5dc0c79ba9cfc659bf5c26bef5a7cbee9e36900e Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 5 Apr 2018 17:15:35 +0200 Subject: [PATCH 25/31] Make repository manager tests more deterministic (still not working on CI though) --- .../Events/RepositoryManagerTests.cs | 358 ++++++++---------- .../Events/IRepositoryManagerListener.cs | 54 +-- 2 files changed, 190 insertions(+), 222 deletions(-) diff --git a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs index b66f55005..d5452f621 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -14,7 +14,7 @@ namespace IntegrationTests { - [TestFixture /*, Category("DoNotRunOnAppVeyor") */] + [TestFixture, Category("DoNotRunOnAppVeyor")] class RepositoryManagerTests : BaseGitEnvironmentTest { private RepositoryManagerEvents repositoryManagerEvents; @@ -95,16 +95,16 @@ public async Task ShouldDetectFileChanges() await repositoryManagerEvents.WaitForNotBusy(); StopTrackTimeAndLog(watch, logger); - (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.GitStatusUpdated); - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.DidNotReceive().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); - repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.DidNotReceive().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.DidNotReceive().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLogUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.CurrentBranchUpdated); } finally { @@ -133,29 +133,29 @@ public async Task ShouldAddAndCommitFiles() var foobarTxt = TestRepoMasterCleanSynchronized.Combine("foobar.txt"); foobarTxt.WriteAllText("foobar"); - var testDocumentTxt = TestRepoMasterCleanSynchronized.Combine("Assets", "TestDocument.txt"); - testDocumentTxt.WriteAllText("foobar"); - - await TaskManager.Wait(); - + StartTrackTime(watch, logger, "RepositoryManager.WaitForEvents()"); RepositoryManager.WaitForEvents(); + StopTrackTimeAndLog(watch, logger); + + StartTrackTime(watch, logger, "repositoryManagerEvents.WaitForNotBusy()"); await repositoryManagerEvents.WaitForNotBusy(); + StopTrackTimeAndLog(watch, logger); - (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.GitStatusUpdated); - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.DidNotReceive().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); - repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.DidNotReceive().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.DidNotReceive().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLogUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.CurrentBranchUpdated); repositoryManagerListener.ClearReceivedCalls(); repositoryManagerEvents.Reset(); - var filesToCommit = new List { "Assets\\TestDocument.txt", "foobar.txt" }; + var filesToCommit = new List { "foobar.txt" }; var commitMessage = "IntegrationTest Commit"; var commitBody = string.Empty; @@ -167,19 +167,16 @@ public async Task ShouldAddAndCommitFiles() RepositoryManager.WaitForEvents(); await repositoryManagerEvents.WaitForNotBusy(); - (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitLogUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.CurrentBranchUpdated); - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); - repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); } finally { @@ -187,6 +184,16 @@ public async Task ShouldAddAndCommitFiles() } } + private async Task AssertReceivedEvent(Task task) + { + (await TaskEx.WhenAny(task, TaskEx.Delay(Timeout))).Should().BeAssignableTo>("otherwise the event was not raised"); + } + + private async Task AssertDidNotReceiveEvent(Task task) + { + (await TaskEx.WhenAny(task, TaskEx.Delay(Timeout))).Should().BeAssignableTo>("otherwise the event was raised"); + } + [Test] public async Task ShouldAddAndCommitAllFiles() { @@ -210,9 +217,6 @@ public async Task ShouldAddAndCommitAllFiles() var foobarTxt = TestRepoMasterCleanSynchronized.Combine("foobar.txt"); foobarTxt.WriteAllText("foobar"); - var testDocumentTxt = TestRepoMasterCleanSynchronized.Combine("Assets", "TestDocument.txt"); - testDocumentTxt.WriteAllText("foobar"); - await TaskManager.Wait(); StartTrackTime(watch, logger, "RepositoryManager.WaitForEvents()"); @@ -223,17 +227,16 @@ public async Task ShouldAddAndCommitAllFiles() await repositoryManagerEvents.WaitForNotBusy(); StopTrackTimeAndLog(watch, logger); - (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.GitStatusUpdated); - repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.DidNotReceive().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); - repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.DidNotReceive().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.DidNotReceive().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLogUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.CurrentBranchUpdated); repositoryManagerListener.ClearReceivedCalls(); repositoryManagerEvents.Reset(); @@ -252,18 +255,16 @@ public async Task ShouldAddAndCommitAllFiles() await repositoryManagerEvents.WaitForNotBusy(); StopTrackTimeAndLog(watch, logger); - (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.GitStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitLogUpdated); + await AssertReceivedEvent(repositoryManagerEvents.CurrentBranchUpdated); - repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); - repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); } finally { @@ -295,20 +296,16 @@ public async Task ShouldDetectBranchChange() RepositoryManager.WaitForEvents(); await repositoryManagerEvents.WaitForNotBusy(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.GitStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitLogUpdated); + await AssertReceivedEvent(repositoryManagerEvents.CurrentBranchUpdated); - repositoryManagerListener.DidNotReceive().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); - repositoryManagerListener.DidNotReceive().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.DidNotReceive().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); } finally { @@ -342,21 +339,16 @@ public async Task ShouldDetectBranchDelete() await TaskEx.Delay(Timeout); - (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitLogUpdated); + await AssertReceivedEvent(repositoryManagerEvents.CurrentBranchUpdated); - repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitStatusUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); } finally { @@ -382,6 +374,16 @@ public async Task ShouldDetectBranchCreate() repositoryManagerListener.AssertDidNotReceiveAnyCalls(); + { + // prepopulate repository info cache + var b = Repository.CurrentBranch; + await TaskManager.Wait(); + RepositoryManager.WaitForEvents(); + await AssertReceivedEvent(repositoryManagerEvents.CurrentBranchUpdated); + repositoryManagerListener.ClearReceivedCalls(); + repositoryManagerEvents.Reset(); + } + var createdBranch1 = "feature/document2"; await RepositoryManager.CreateBranch(createdBranch1, "feature/document").StartAsAsync(); await TaskManager.Wait(); @@ -389,21 +391,17 @@ public async Task ShouldDetectBranchCreate() RepositoryManager.WaitForEvents(); await repositoryManagerEvents.WaitForNotBusy(); - (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); - repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); + // we don't expect these events // TODO: log should not be getting called, but it is because when branches get changed we're blindly calling log - //repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); + //await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLogUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitStatusUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.CurrentBranchUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); repositoryManagerListener.ClearReceivedCalls(); repositoryManagerEvents.Reset(); @@ -417,20 +415,17 @@ public async Task ShouldDetectBranchCreate() await repositoryManagerEvents.WaitForNotBusy(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); - repositoryManagerListener.DidNotReceive().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitStatusUpdated); // TODO: log should not be getting called, but it is because when branches get changed we're blindly calling log - //repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); + //await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLogUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.CurrentBranchUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); } finally { @@ -462,21 +457,16 @@ public async Task ShouldDetectChangesToRemotes() RepositoryManager.WaitForEvents(); await repositoryManagerEvents.WaitForNotBusy(); - (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitLogUpdated); + await AssertReceivedEvent(repositoryManagerEvents.CurrentBranchUpdated); - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); - - repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitStatusUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); repositoryManagerListener.ClearReceivedCalls(); repositoryManagerEvents.Reset(); @@ -487,21 +477,16 @@ public async Task ShouldDetectChangesToRemotes() RepositoryManager.WaitForEvents(); await repositoryManagerEvents.WaitForNotBusy(); - (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitLogUpdated); + await AssertReceivedEvent(repositoryManagerEvents.CurrentBranchUpdated); - repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitStatusUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); } finally { @@ -533,21 +518,16 @@ public async Task ShouldDetectChangesToRemotesWhenSwitchingBranches() RepositoryManager.WaitForEvents(); await repositoryManagerEvents.WaitForNotBusy(); - (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitLogUpdated); + await AssertReceivedEvent(repositoryManagerEvents.CurrentBranchUpdated); - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); - - repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitStatusUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); repositoryManagerListener.ClearReceivedCalls(); repositoryManagerEvents.Reset(); @@ -558,20 +538,16 @@ public async Task ShouldDetectChangesToRemotesWhenSwitchingBranches() RepositoryManager.WaitForEvents(); await repositoryManagerEvents.WaitForNotBusy(); - (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.GitStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitLogUpdated); + await AssertReceivedEvent(repositoryManagerEvents.CurrentBranchUpdated); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); - repositoryManagerListener.DidNotReceive().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.DidNotReceive().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); } finally { @@ -603,22 +579,17 @@ public async Task ShouldDetectGitPull() RepositoryManager.WaitForEvents(); await repositoryManagerEvents.WaitForNotBusy(); - (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitLogUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.Received().GitLogUpdated(Args.GitLogs); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.GitStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitLogUpdated); + await AssertReceivedEvent(repositoryManagerEvents.CurrentBranchUpdated); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); + // we don't expect these events // TODO: this should not happen but it's happening right now because when local branches get updated in the cache, remotes get updated too - //repositoryManagerListener.DidNotReceive().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + //await AssertDidNotReceiveEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); } finally { @@ -650,21 +621,18 @@ public async Task ShouldDetectGitFetch() RepositoryManager.WaitForEvents(); await repositoryManagerEvents.WaitForNotBusy(); - (await TaskEx.WhenAny(repositoryManagerEvents.CurrentBranchUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.GitAheadBehindStatusUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.LocalBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - (await TaskEx.WhenAny(repositoryManagerEvents.RemoteBranchesUpdated, TaskEx.Delay(Timeout))).Should().BeAssignableTo>(); - - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); - repositoryManagerListener.Received().GitAheadBehindStatusUpdated(Args.GitAheadBehindStatus); - repositoryManagerListener.Received().LocalBranchesUpdated(Args.LocalBranchDictionary); - repositoryManagerListener.Received().RemoteBranchesUpdated(Args.RemoteDictionary, Args.RemoteBranchDictionary); + // we expect these events + await AssertReceivedEvent(repositoryManagerEvents.LocalBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.RemoteBranchesUpdated); + await AssertReceivedEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertReceivedEvent(repositoryManagerEvents.CurrentBranchUpdated); - repositoryManagerListener.DidNotReceive().GitStatusUpdated(Args.GitStatus); - repositoryManagerListener.DidNotReceive().GitLocksUpdated(Args.GitLocks); + // we don't expect these events + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitStatusUpdated); // TODO: log should not be getting called, but it is because when branches get changed we're blindly calling log - //repositoryManagerListener.DidNotReceive().GitLogUpdated(Args.GitLogs); + //await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLogUpdated); + //await AssertDidNotReceiveEvent(repositoryManagerEvents.GitAheadBehindStatusUpdated); + await AssertDidNotReceiveEvent(repositoryManagerEvents.GitLocksUpdated); } finally { diff --git a/src/tests/TestUtils/Events/IRepositoryManagerListener.cs b/src/tests/TestUtils/Events/IRepositoryManagerListener.cs index ad953b643..240996b82 100644 --- a/src/tests/TestUtils/Events/IRepositoryManagerListener.cs +++ b/src/tests/TestUtils/Events/IRepositoryManagerListener.cs @@ -24,24 +24,24 @@ interface IRepositoryManagerListener class RepositoryManagerEvents { - internal TaskCompletionSource isBusy; - public Task IsBusy => isBusy.Task; - internal TaskCompletionSource isNotBusy; - public Task IsNotBusy => isNotBusy.Task; - internal TaskCompletionSource currentBranchUpdated; - public Task CurrentBranchUpdated => currentBranchUpdated.Task; - internal TaskCompletionSource gitAheadBehindStatusUpdated; - public Task GitAheadBehindStatusUpdated => gitAheadBehindStatusUpdated.Task; - internal TaskCompletionSource gitStatusUpdated; - public Task GitStatusUpdated => gitStatusUpdated.Task; - internal TaskCompletionSource gitLocksUpdated; - public Task GitLocksUpdated => gitLocksUpdated.Task; - internal TaskCompletionSource gitLogUpdated; - public Task GitLogUpdated => gitLogUpdated.Task; - internal TaskCompletionSource localBranchesUpdated; - public Task LocalBranchesUpdated => localBranchesUpdated.Task; - internal TaskCompletionSource remoteBranchesUpdated; - public Task RemoteBranchesUpdated => remoteBranchesUpdated.Task; + internal TaskCompletionSource isBusy; + public Task IsBusy => isBusy.Task; + internal TaskCompletionSource isNotBusy; + public Task IsNotBusy => isNotBusy.Task; + internal TaskCompletionSource currentBranchUpdated; + public Task CurrentBranchUpdated => currentBranchUpdated.Task; + internal TaskCompletionSource gitAheadBehindStatusUpdated; + public Task GitAheadBehindStatusUpdated => gitAheadBehindStatusUpdated.Task; + internal TaskCompletionSource gitStatusUpdated; + public Task GitStatusUpdated => gitStatusUpdated.Task; + internal TaskCompletionSource gitLocksUpdated; + public Task GitLocksUpdated => gitLocksUpdated.Task; + internal TaskCompletionSource gitLogUpdated; + public Task GitLogUpdated => gitLogUpdated.Task; + internal TaskCompletionSource localBranchesUpdated; + public Task LocalBranchesUpdated => localBranchesUpdated.Task; + internal TaskCompletionSource remoteBranchesUpdated; + public Task RemoteBranchesUpdated => remoteBranchesUpdated.Task; public RepositoryManagerEvents() @@ -51,15 +51,15 @@ public RepositoryManagerEvents() public void Reset() { - isBusy = new TaskCompletionSource(); - isNotBusy = new TaskCompletionSource(); - currentBranchUpdated = new TaskCompletionSource(); - gitAheadBehindStatusUpdated = new TaskCompletionSource(); - gitStatusUpdated = new TaskCompletionSource(); - gitLocksUpdated = new TaskCompletionSource(); - gitLogUpdated = new TaskCompletionSource(); - localBranchesUpdated = new TaskCompletionSource(); - remoteBranchesUpdated = new TaskCompletionSource(); + isBusy = new TaskCompletionSource(); + isNotBusy = new TaskCompletionSource(); + currentBranchUpdated = new TaskCompletionSource(); + gitAheadBehindStatusUpdated = new TaskCompletionSource(); + gitStatusUpdated = new TaskCompletionSource(); + gitLocksUpdated = new TaskCompletionSource(); + gitLogUpdated = new TaskCompletionSource(); + localBranchesUpdated = new TaskCompletionSource(); + remoteBranchesUpdated = new TaskCompletionSource(); } public async Task WaitForNotBusy(int seconds = 1) From 7540d7c823244843a32480fce3b172b86c1fe516 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 5 Apr 2018 19:55:25 +0200 Subject: [PATCH 26/31] Always return valid data from the downloader --- src/GitHub.Api/Managers/Downloader.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/GitHub.Api/Managers/Downloader.cs b/src/GitHub.Api/Managers/Downloader.cs index 93bd5ead4..6f0fb2fa9 100644 --- a/src/GitHub.Api/Managers/Downloader.cs +++ b/src/GitHub.Api/Managers/Downloader.cs @@ -70,6 +70,7 @@ class PairDownloader private int finishedTaskCount; private volatile bool isSuccessful = true; private volatile Exception exception; + private DownloadData result; public PairDownloader() { @@ -84,7 +85,7 @@ public Task Run() foreach (var task in queuedTasks) task.Start(); if (queuedTasks.Count == 0) - DownloadComplete(null); + DownloadComplete(result); return aggregateDownloads.Task; } @@ -92,7 +93,7 @@ public Task QueueDownload(UriString url, UriString md5Url, NPath t { var destinationFile = targetDirectory.Combine(url.Filename); var destinationMd5 = targetDirectory.Combine(md5Url.Filename); - var result = new DownloadData(url, destinationFile); + result = new DownloadData(url, destinationFile); Action, NPath, bool, Exception> verifyDownload = (t, res, success, ex) => { From d77f043e6b432ac7552a378d8bd478483e300711 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 5 Apr 2018 19:56:17 +0200 Subject: [PATCH 27/31] Continuations are set at the end of the task run --- src/GitHub.Api/Tasks/TaskBase.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index e70f20035..87c0cb9ea 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -316,7 +316,6 @@ public virtual ITask Start(TaskScheduler scheduler) { //Logger.Trace($"Starting {Affinity} {ToString()}"); Task.Start(scheduler); - SetContinuation(); } return this; } From a681d183f52eb1bc4676feb05b8289cbe67c7319 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 5 Apr 2018 19:57:26 +0200 Subject: [PATCH 28/31] Add some comments and set some windows-only env vars only on windows --- src/GitHub.Api/Platform/ProcessEnvironment.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/GitHub.Api/Platform/ProcessEnvironment.cs b/src/GitHub.Api/Platform/ProcessEnvironment.cs index 259d828b7..b78c5fdbb 100644 --- a/src/GitHub.Api/Platform/ProcessEnvironment.cs +++ b/src/GitHub.Api/Platform/ProcessEnvironment.cs @@ -65,10 +65,13 @@ public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSet { pathEntries.Add(gitExecutableDir.ToString()); } + if (execPath.IsInitialized) pathEntries.Add(execPath); pathEntries.Add(binPath); + // we can only set this env var if there is a libexec/git-core. git will bypass internally bundled tools if this env var + // is set, which will break Apple's system git on certain tools (like osx-credentialmanager) if (execPath.IsInitialized) psi.EnvironmentVariables["GIT_EXEC_PATH"] = execPath.ToString(); } @@ -88,8 +91,11 @@ public void Configure(ProcessStartInfo psi, NPath workingDirectory, bool dontSet //TODO: Remove with Git LFS Locking becomes standard psi.EnvironmentVariables["GITLFSLOCKSENABLED"] = "1"; - psi.EnvironmentVariables["PLINK_PROTOCOL"] = "ssh"; - psi.EnvironmentVariables["TERM"] = "msys"; + if (Environment.IsWindows) + { + psi.EnvironmentVariables["PLINK_PROTOCOL"] = "ssh"; + psi.EnvironmentVariables["TERM"] = "msys"; + } var httpProxy = Environment.GetEnvironmentVariable("HTTP_PROXY"); if (!String.IsNullOrEmpty(httpProxy)) From 39d7f45cacd9fa1ff040186ce8271db87c9a8c37 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 5 Apr 2018 19:58:45 +0200 Subject: [PATCH 29/31] We need to propagate finally handlers for ITask types as well --- src/GitHub.Api/Tasks/TaskBase.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index 87c0cb9ea..b959c530e 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -550,7 +550,20 @@ protected TaskBase(Task task) public override T Then(T continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess, bool taskIsTopOfChain = false) { - return base.Then(continuation, runOptions, taskIsTopOfChain); + var nextTask = base.Then(continuation, runOptions, taskIsTopOfChain); + var nextTaskBase = ((TaskBase)(object)nextTask); + // if the current task has a fault handler that matches this signature, attach it to the chain we're appending + if (finallyHandler != null) + { + TaskBase endOfChainTask = (TaskBase)nextTaskBase.GetEndOfChain(); + while (endOfChainTask != this && endOfChainTask != null) + { + if (endOfChainTask is TaskBase) + ((TaskBase)endOfChainTask).finallyHandler += finallyHandler; + endOfChainTask = endOfChainTask.DependsOn; + } + } + return nextTask; } /// From a500ff248aeeacdb268015e080c6d3c03a704156 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 5 Apr 2018 19:59:24 +0200 Subject: [PATCH 30/31] Fix a problem with the git installation process The installation state was getting passed into ExtractPortableGit too early - that method needs to have the result of the download tasks --- src/GitHub.Api/Installer/GitInstaller.cs | 76 +++++++++++++------ src/GitHub.Api/Managers/Downloader.cs | 29 +------ .../Installer/GitInstallerTests.cs | 8 +- 3 files changed, 60 insertions(+), 53 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 480740656..469b13437 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -30,14 +30,13 @@ public GitInstaller(IEnvironment environment, IProcessManager processManager, public ITask SetupGitIfNeeded() { //Logger.Trace("SetupGitIfNeeded"); - + GitInstallationState installationState = new GitInstallationState(); installationTask = new FuncTask(cancellationToken, (success, path) => path) { Name = "Git Installation - Complete" }; installationTask.OnStart += thisTask => thisTask.UpdateProgress(0, 100); installationTask.OnEnd += (thisTask, result, success, exception) => thisTask.UpdateProgress(100, 100); ITask startTask = null; - GitInstallationState installationState = new GitInstallationState(); if (!environment.IsWindows) { var findTask = new FindExecTask("git", cancellationToken) @@ -72,37 +71,47 @@ public ITask SetupGitIfNeeded() { startTask = new FuncTask(cancellationToken, () => { - installationState = VerifyGitInstallation(); - if (!installationState.GitIsValid && !installationState.GitLfsIsValid) - installationState = GrabZipFromResources(installationState); - else - Logger.Trace("SetupGitIfNeeded: Skipped"); - return installationState; + return VerifyPortableGitInstallation(); }) { Name = "Git Installation - Extract" }; } + startTask = startTask.Then(new FuncTask(cancellationToken, (success, installState) => + { + if (installState.GitIsValid && installState.GitLfsIsValid) + { + return installState; + } + + installState = VerifyZipFiles(installState); + installState = GrabZipFromResourcesIfNeeded(installState); + return installState; + }) + { Name = "Git Installation - Validate" } + ); + startTask.OnEnd += (thisTask, installState, success, exception) => { - if (!installState.GitIsValid && !installState.GitLfsIsValid) + if (installState.GitIsValid && installState.GitLfsIsValid) { - if (!installState.GitZipExists || !installState.GitLfsZipExists) - thisTask = thisTask.Then(CreateDownloadTask(installState)); - thisTask = thisTask.Then(ExtractPortableGit(installState)); + Logger.Trace("Skipping git installation"); + thisTask.Then(installationTask); + return; } - thisTask = thisTask.Then(installationTask); + + var downloadZipTask = DownloadZipsIfNeeded(installState); + downloadZipTask.OnEnd += ExtractPortableGit; + thisTask.Then(downloadZipTask); }; return startTask; } - private GitInstallationState VerifyGitInstallation() + private GitInstallationState VerifyPortableGitInstallation() { var state = new GitInstallationState(); var gitExists = installDetails.GitExecutablePath.IsInitialized && installDetails.GitExecutablePath.FileExists(); var gitLfsExists = installDetails.GitLfsExecutablePath.IsInitialized && installDetails.GitLfsExecutablePath.FileExists(); - state.GitZipExists = installDetails.GitZipPath.FileExists(); - state.GitLfsZipExists = installDetails.GitLfsZipPath.FileExists(); if (gitExists) { @@ -144,26 +153,44 @@ private GitInstallationState VerifyGitInstallation() return state; } - private GitInstallationState GrabZipFromResources(GitInstallationState state) + private GitInstallationState VerifyZipFiles(GitInstallationState state) + { + var md5 = AssemblyResources.ToFile(ResourceType.Platform, "git.zip.md5", installDetails.ZipPath, environment); + if (!md5.FileExists() || (installDetails.GitZipPath.FileExists() && !Utils.VerifyFileIntegrity(installDetails.GitZipPath, md5))) + { + installDetails.GitZipPath.DeleteIfExists(); + } + state.GitZipExists = installDetails.GitZipPath.FileExists(); + + md5 = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip.md5", installDetails.ZipPath, environment); + // check whether the git-lfs zip file exists and is valid + if (!md5.FileExists() || (installDetails.GitLfsZipPath.FileExists() && !Utils.VerifyFileIntegrity(installDetails.GitLfsZipPath, md5))) + { + installDetails.GitLfsZipPath.DeleteIfExists(); + } + state.GitLfsZipExists = installDetails.GitLfsZipPath.FileExists(); + installationTask.UpdateProgress(20, 100); + return state; + } + + private GitInstallationState GrabZipFromResourcesIfNeeded(GitInstallationState state) { if (!state.GitZipExists) { AssemblyResources.ToFile(ResourceType.Platform, "git.zip", installDetails.ZipPath, environment); - AssemblyResources.ToFile(ResourceType.Platform, "git.zip.md5", installDetails.ZipPath, environment); } state.GitZipExists = installDetails.GitZipPath.FileExists(); if (!state.GitLfsZipExists) { AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", installDetails.ZipPath, environment); - AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip.md5", installDetails.ZipPath, environment); } state.GitLfsZipExists = installDetails.GitLfsZipPath.FileExists(); - installationTask.UpdateProgress(20, 100); + installationTask.UpdateProgress(30, 100); return state; } - private ITask CreateDownloadTask(GitInstallationState state) + private ITask DownloadZipsIfNeeded(GitInstallationState state) { var downloader = new Downloader(); downloader.Catch(e => true); @@ -180,7 +207,8 @@ private ITask CreateDownloadTask(GitInstallationState stat }); } - private FuncTask ExtractPortableGit(GitInstallationState state) + private void ExtractPortableGit(ITask thisTask, + GitInstallationState state, bool s, Exception exception) { ITask task = null; var tempZipExtractPath = NPath.CreateTempDirectory("git_zip_extract_zip_paths"); @@ -252,7 +280,9 @@ private FuncTask ExtractPortableGit(GitInstallationState s endTask = task.Then(endTask); } - return endTask; + thisTask + .Then(endTask) + .Then(installationTask); } public class GitInstallationState diff --git a/src/GitHub.Api/Managers/Downloader.cs b/src/GitHub.Api/Managers/Downloader.cs index 6f0fb2fa9..b4fcbc342 100644 --- a/src/GitHub.Api/Managers/Downloader.cs +++ b/src/GitHub.Api/Managers/Downloader.cs @@ -29,7 +29,9 @@ class Downloader : FuncListTask private readonly List downloaders = new List(); public Downloader() : base(TaskManager.Instance.Token, RunDownloaders) - {} + { + Name = "Downloader"; + } public void QueueDownload(UriString url, UriString md5Url, NPath targetDirectory) { @@ -124,31 +126,6 @@ public Task QueueDownload(UriString url, UriString md5Url, NPath t var md5Exists = destinationMd5.FileExists(); var fileExists = destinationFile.FileExists(); - if (fileExists && md5Exists) - { - var verification = new FuncTask(cancellationToken, () => destinationFile); - verification.OnStart += _ => DownloadStart?.Invoke(result); - verification.OnEnd += (t, res, success, ex) => - { - if (!Utils.VerifyFileIntegrity(destinationFile, destinationMd5)) - { - destinationMd5.Delete(); - destinationFile.Delete(); - var fileDownload = DownloadFile(url, targetDirectory, result, verifyDownload); - queuedTasks.Add(fileDownload); - var md5Download = DownloadFile(md5Url, targetDirectory, result, verifyDownload); - queuedTasks.Add(md5Download); - fileDownload.Start(); - md5Download.Start(); - } - else - { - DownloadComplete(result); - } - }; - queuedTasks.Add(verification); - } - if (!md5Exists) { var md5Download = DownloadFile(md5Url, targetDirectory, result, verifyDownload); diff --git a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs index e1f48f6a5..05bedd749 100644 --- a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs +++ b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs @@ -62,12 +62,12 @@ public void GitInstallWindows() }), Arg.Any(), Arg.Any>()).Returns(true); ZipHelper.Instance = zipHelper; var gitInstaller = new GitInstaller(Environment, ProcessManager, TaskManager, installDetails); - var startTask = gitInstaller.SetupGitIfNeeded(); - var endTask = new FuncTask(TaskManager.Token, (s, state) => state); - startTask.OnEnd += (thisTask, path, success, exception) => thisTask.GetEndOfChain().Then(endTask); + + TaskCompletionSource end = new TaskCompletionSource(); + var startTask = gitInstaller.SetupGitIfNeeded().Finally((_, state) => end.TrySetResult(state)); startTask.Start(); GitInstaller.GitInstallationState result = null; - Assert.DoesNotThrow(async () => result = await endTask.Task); + Assert.DoesNotThrow(async () => result = await end.Task); result.Should().NotBeNull(); Assert.AreEqual(gitInstallationPath.Combine(installDetails.PackageNameWithVersion), result.GitInstallationPath); From ba24c199ddd838a32cd9d3475ef3fcb8bac13b20 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 5 Apr 2018 20:28:24 +0200 Subject: [PATCH 31/31] Fix integration test git installer step --- src/tests/IntegrationTests/BaseIntegrationTest.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/tests/IntegrationTests/BaseIntegrationTest.cs b/src/tests/IntegrationTests/BaseIntegrationTest.cs index 351782194..8e41ca6b6 100644 --- a/src/tests/IntegrationTests/BaseIntegrationTest.cs +++ b/src/tests/IntegrationTests/BaseIntegrationTest.cs @@ -8,6 +8,7 @@ using System.Linq; using System.IO; using System.Runtime.CompilerServices; +using System.Threading.Tasks; namespace IntegrationTests { @@ -160,16 +161,13 @@ protected void SetupGit(NPath pathToSetupGitInto, string testName) NPath? result = null; Exception ex = null; - var setupTask = gitInstaller.SetupGitIfNeeded(); - setupTask.OnEnd += (thisTask, _, __, ___) => { - ((ITask)thisTask.GetEndOfChain()).OnEnd += (t, state, success, exception) => + var setupTask = gitInstaller.SetupGitIfNeeded().Finally((success, state) => { result = state.GitExecutablePath; - ex = exception; autoResetEvent.Set(); - }; - }; + }); setupTask.Start(); + if (!autoResetEvent.WaitOne(TimeSpan.FromMinutes(5))) throw new TimeoutException($"Test setup unzipping {zipArchivesPath} to {pathToSetupGitInto} timed out");