From bdf6e00c77991305a0a8fe036b3601b54d308b1f Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 7 Nov 2017 17:16:47 -0500 Subject: [PATCH 0001/1008] Adding test to parse ssh based url --- .../IO/RemoteListOutputProcessorTests.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/tests/UnitTests/IO/RemoteListOutputProcessorTests.cs b/src/tests/UnitTests/IO/RemoteListOutputProcessorTests.cs index 1d3b015a6..aaec24dcf 100644 --- a/src/tests/UnitTests/IO/RemoteListOutputProcessorTests.cs +++ b/src/tests/UnitTests/IO/RemoteListOutputProcessorTests.cs @@ -28,6 +28,27 @@ public void ShouldParseSingleHttpsBothWaysRemote() }); } + [Test] + public void ShouldParseSingleSshBothWaysRemote() + { + var output = new[] + { + "origin git@github.com:github-for-unity/Unity.git (fetch)", + "origin git@github.com:github-for-unity/Unity.git (push)", + null + }; + + var name = "origin"; + var host = "github.com"; + var url = "github.com:github-for-unity/Unity.git"; + var function = GitRemoteFunction.Both; + var user = "git"; + AssertProcessOutput(output, new[] + { + new GitRemote(name, host, url, function, user) + }); + } + [Test] public void ShouldParseSingleHttpsFetchOnlyRemote() { From 975357bd0825b53e8465fd897f58e1968ece4305 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 21 Nov 2017 08:54:29 -0500 Subject: [PATCH 0002/1008] Changing project files to link to codeanalysis-small.ruleset --- src/GitHub.Api/GitHub.Api.csproj | 12 ++++++------ src/GitHub.Logging/GitHub.Logging.csproj | 6 ++++++ .../Assets/Editor/GitHub.Unity/GitHub.Unity.csproj | 10 ++++++---- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 2816e0140..3cdb69568 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -26,8 +26,8 @@ DEBUG;TRACE prompt 4 - false - ..\..\common\codeanalysis-small.ruleset + true + $(SolutionDir)\common\codeanalysis-small.ruleset false true @@ -37,8 +37,8 @@ TRACE prompt 4 - false - MinimumRecommendedRules.ruleset + true + $(SolutionDir)\common\codeanalysis-small.ruleset false true Release @@ -50,8 +50,8 @@ TRACE;DEBUG;DEVELOPER_BUILD prompt 4 - false - MinimumRecommendedRules.ruleset + true + $(SolutionDir)\common\codeanalysis-small.ruleset false true diff --git a/src/GitHub.Logging/GitHub.Logging.csproj b/src/GitHub.Logging/GitHub.Logging.csproj index 2f52b9f73..b4d9815e0 100644 --- a/src/GitHub.Logging/GitHub.Logging.csproj +++ b/src/GitHub.Logging/GitHub.Logging.csproj @@ -21,6 +21,8 @@ DEBUG;TRACE prompt 4 + true + $(SolutionDir)\common\codeanalysis-small.ruleset AnyCPU @@ -30,6 +32,8 @@ TRACE prompt 4 + true + $(SolutionDir)\common\codeanalysis-small.ruleset Release @@ -44,6 +48,8 @@ DEBUG;TRACE;DEVELOPER_BUILD prompt 4 + true + $(SolutionDir)\common\codeanalysis-small.ruleset Debug diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj index ac26b427b..23b651d7e 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj @@ -22,8 +22,8 @@ DEBUG;TRACE prompt 4 - false - ..\..\..\..\..\common\codeanalysis-small.ruleset + true + $(SolutionDir)\common\codeanalysis-small.ruleset 4 @@ -32,6 +32,8 @@ TRACE prompt 4 + true + $(SolutionDir)\common\codeanalysis-small.ruleset Release @@ -41,8 +43,8 @@ DEBUG;TRACE;DEVELOPER_BUILD prompt 4 - false - $(SolutionDir)common\GitHub.ruleset + true + $(SolutionDir)\common\codeanalysis-small.ruleset 4 From 74b9c57e58d4df6fad88905e8111c0f7abcab9ae Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 18 Dec 2017 14:00:56 -0500 Subject: [PATCH 0003/1008] Separating adding general support for nodes that are containers but not folders --- src/GitHub.Api/UI/TreeBase.cs | 38 ++++++++++--------- .../GitHub.Unity/UI/ChangesTreeControl.cs | 2 +- .../Editor/GitHub.Unity/UI/TreeControl.cs | 29 ++++++++++---- src/tests/UnitTests/UI/TreeBaseTests.cs | 10 +++-- 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/GitHub.Api/UI/TreeBase.cs b/src/GitHub.Api/UI/TreeBase.cs index c810c72c4..5f581b915 100644 --- a/src/GitHub.Api/UI/TreeBase.cs +++ b/src/GitHub.Api/UI/TreeBase.cs @@ -16,7 +16,9 @@ public interface ITreeNode string Path { get; set; } string Label { get; set; } int Level { get; set; } + bool IsContainer { get; set; } bool IsFolder { get; set; } + bool IsFolderOrContainer { get; } bool IsCollapsed { get; set; } bool IsHidden { get; set; } bool IsActive { get; set; } @@ -51,7 +53,7 @@ public void Load(IEnumerable treeDatas) var isCheckable = IsCheckable; var isSelected = IsSelectable && selectedNodePath != null && Title == selectedNodePath; - AddNode(Title, Title, -1 + displayRootLevel, true, false, false, false, isSelected, false, null); + AddNode(Title, Title, -1 + displayRootLevel, true, false, false, false, isSelected, false, null, false); var hideChildren = false; var hideChildrenBelowLevel = 0; @@ -112,7 +114,7 @@ public void Load(IEnumerable treeDatas) isSelected = selectedNodePath != null && nodePath == selectedNodePath; AddNode(nodePath, label, i + displayRootLevel, isFolder, isActive, nodeIsHidden, - nodeIsCollapsed, isSelected, isChecked, treeNodeTreeData); + nodeIsCollapsed, isSelected, isChecked, treeNodeTreeData, false); } } } @@ -123,7 +125,7 @@ public void Load(IEnumerable treeDatas) for (var index = nodes.Count - 1; index >= 0; index--) { var node = nodes[index]; - if (node.Level >= 0 && node.IsFolder) + if (node.Level >= 0 && node.IsFolderOrContainer) { bool? anyChecked = null; bool? allChecked = null; @@ -173,9 +175,9 @@ public void SetCheckStateOnAll(bool isChecked) protected abstract IEnumerable GetCollapsedFolders(); - protected void AddNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, bool isSelected, bool isChecked, TData? treeData) + protected void AddNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, bool isSelected, bool isChecked, TData? treeData, bool isContainer) { - var node = CreateTreeNode(path, label, level, isFolder, isActive, isHidden, isCollapsed, isChecked, treeData); + var node = CreateTreeNode(path, label, level, isFolder, isActive, isHidden, isCollapsed, isChecked, treeData, isContainer); SetNodeIcon(node); Nodes.Add(node); @@ -197,7 +199,7 @@ protected void Clear() protected abstract void AddCheckedNode(TNode node); - protected abstract TNode CreateTreeNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, bool isChecked, TData? treeData); + protected abstract TNode CreateTreeNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, bool isChecked, TData? treeData, bool isContainer); protected abstract void OnClear(); @@ -211,7 +213,7 @@ protected void ToggleNodeVisibility(int idx, TNode node) for (; idx < Nodes.Count && Nodes[idx].Level > nodeLevel; idx++) { Nodes[idx].IsHidden = node.IsCollapsed; - if (Nodes[idx].IsFolder && !node.IsCollapsed && Nodes[idx].IsCollapsed) + if (Nodes[idx].IsFolderOrContainer && !node.IsCollapsed && Nodes[idx].IsCollapsed) { var level = Nodes[idx].Level; for (idx++; idx < Nodes.Count && Nodes[idx].Level > level; idx++) @@ -244,11 +246,7 @@ protected void ToggleNodeChecked(int idx, TNode node) break; } - if (node.IsFolder) - { - ToggleChildrenChecked(idx, node, isChecked); - } - else + if (!node.IsFolder) { if (isChecked) { @@ -260,6 +258,11 @@ protected void ToggleNodeChecked(int idx, TNode node) } } + if (node.IsFolderOrContainer) + { + ToggleChildrenChecked(idx, node, isChecked); + } + ToggleParentFoldersChecked(idx, node, isChecked); } @@ -271,11 +274,7 @@ private void ToggleChildrenChecked(int idx, TNode node, bool isChecked) var wasChecked = childNode.CheckState == CheckState.Checked; childNode.CheckState = isChecked ? CheckState.Checked : CheckState.Empty; - if (childNode.IsFolder) - { - ToggleChildrenChecked(i, childNode, isChecked); - } - else + if (!childNode.IsFolder) { if (isChecked && !wasChecked) { @@ -286,6 +285,11 @@ private void ToggleChildrenChecked(int idx, TNode node, bool isChecked) RemoveCheckedNode(childNode); } } + + if (childNode.IsFolderOrContainer) + { + ToggleChildrenChecked(i, childNode, isChecked); + } } } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs index a648f9509..930e84c1b 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs @@ -189,7 +189,7 @@ protected Texture GetNodeIconBadge(ChangesTreeNode node) return Styles.GetFileStatusIcon(gitFileStatus, node.IsLocked); } - protected override ChangesTreeNode CreateTreeNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, bool isChecked, GitStatusEntryTreeData? treeData) + protected override ChangesTreeNode CreateTreeNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, bool isChecked, GitStatusEntryTreeData? treeData, bool isContainer) { var gitFileStatus = GitFileStatus.None; var projectPath = (string) null; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/TreeControl.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/TreeControl.cs index 22710594a..9cdcc8b31 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/TreeControl.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/TreeControl.cs @@ -240,7 +240,7 @@ private bool HandleInput(Rect rect, TNode currentNode, int index, Action } else if (directionX > 0) { - if (currentNode.IsFolder && currentNode.IsCollapsed) + if (currentNode.IsFolderOrContainer && currentNode.IsCollapsed) { ToggleNodeVisibility(index, currentNode); } @@ -251,7 +251,7 @@ private bool HandleInput(Rect rect, TNode currentNode, int index, Action } else if (directionX < 0) { - if (currentNode.IsFolder && !currentNode.IsCollapsed) + if (currentNode.IsFolderOrContainer && !currentNode.IsCollapsed) { ToggleNodeVisibility(index, currentNode); } @@ -274,13 +274,13 @@ private bool HandleInput(Rect rect, TNode currentNode, int index, Action return requiresRepaint; } - private int SelectNext(int index, bool foldersOnly) + private int SelectNext(int index, bool foldersOrContainersOnly) { for (index++; index < Nodes.Count; index++) { if (Nodes[index].IsHidden) continue; - if (!Nodes[index].IsFolder && foldersOnly) + if (!Nodes[index].IsFolderOrContainer && foldersOrContainersOnly) continue; break; } @@ -296,13 +296,13 @@ private int SelectNext(int index, bool foldersOnly) return index; } - private int SelectPrevious(int index, bool foldersOnly) + private int SelectPrevious(int index, bool foldersOrContainersOnly) { for (index--; index >= 0; index--) { if (Nodes[index].IsHidden) continue; - if (!Nodes[index].IsFolder && foldersOnly) + if (!Nodes[index].IsFolderOrContainer && foldersOrContainersOnly) continue; break; } @@ -344,6 +344,7 @@ public class TreeNode : ITreeNode public string label; public int level; public bool isFolder; + public bool isContainer; public bool isCollapsed; public bool isHidden; public bool isActive; @@ -372,12 +373,23 @@ public int Level set { level = value; } } + public bool IsContainer + { + get { return isContainer; } + set { isContainer = value; } + } + public bool IsFolder { get { return isFolder; } set { isFolder = value; } } + public bool IsFolderOrContainer + { + get { return IsFolder || IsContainer; } + } + public bool IsCollapsed { get { return isCollapsed; } @@ -459,7 +471,7 @@ public TreeNodeRenderResult Render(Rect rect, float indentation, bool isSelected } var styleOn = false; - if (IsFolder) + if (IsFolderOrContainer) { styleOn = !IsCollapsed; @@ -643,13 +655,14 @@ protected Texture GetNodeIcon(TreeNode node) return nodeIcon; } - protected override TreeNode CreateTreeNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, bool isChecked, GitBranchTreeData? treeData) + protected override TreeNode CreateTreeNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, bool isChecked, GitBranchTreeData? treeData, bool isContainer) { var node = new TreeNode { Path = path, Label = label, Level = level, IsFolder = isFolder, + IsContainer = isContainer, IsActive = isActive, IsHidden = isHidden, IsCollapsed = isCollapsed, diff --git a/src/tests/UnitTests/UI/TreeBaseTests.cs b/src/tests/UnitTests/UI/TreeBaseTests.cs index 67091bbaf..98f99ccc3 100644 --- a/src/tests/UnitTests/UI/TreeBaseTests.cs +++ b/src/tests/UnitTests/UI/TreeBaseTests.cs @@ -14,7 +14,13 @@ public class TestTreeNode : ITreeNode public string Path { get; set; } public string Label { get; set; } public int Level { get; set; } + + public bool IsContainer { get; set; } + public bool IsFolder { get; set; } + + public bool IsFolderOrContainer => IsFolder || IsContainer; + public bool IsCollapsed { get; set; } public bool IsHidden { get; set; } public bool IsActive { get; set; } @@ -106,8 +112,7 @@ protected override void AddCheckedNode(TestTreeNode node) TestTreeListener.AddCheckedNode(node); } - protected override TestTreeNode CreateTreeNode(string path, string label, int level, bool isFolder, - bool isActive, bool isHidden, bool isCollapsed, bool isChecked, TestTreeData? treeData) + protected override TestTreeNode CreateTreeNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, bool isChecked, TestTreeData? treeData, bool isContainer) { if (traceLogging) { @@ -471,7 +476,6 @@ public void ShouldPopulateTreeWithSingleEntryInPath() }); } - [Test] public void ShouldPopulateTreeWithTwoEntriesInPath() { From 994d52f2241abc7aea7b5dc0b5a44cbd87cb2176 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 18 Dec 2017 14:05:05 -0500 Subject: [PATCH 0004/1008] Adding blank test with initial conditions --- src/tests/UnitTests/UI/TreeBaseTests.cs | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/tests/UnitTests/UI/TreeBaseTests.cs b/src/tests/UnitTests/UI/TreeBaseTests.cs index 98f99ccc3..38f62946b 100644 --- a/src/tests/UnitTests/UI/TreeBaseTests.cs +++ b/src/tests/UnitTests/UI/TreeBaseTests.cs @@ -534,6 +534,64 @@ public void ShouldPopulateTreeWithTwoEntriesInPath() }); } + [Test] + public void ShouldPopulateTreeWithSingleEntryWithMetaInPath() + { + var testTree = new TestTree(true); + var testTreeListener = testTree.TestTreeListener; + + testTreeListener.GetCollapsedFolders().Returns(new string[0]); + testTreeListener.SelectedNode.Returns((TestTreeNode)null); + testTreeListener.GetCheckedFiles().Returns(new string[0]); + testTreeListener.Nodes.Returns(new List()); + testTreeListener.PathSeparator.Returns(@"\"); + testTreeListener.DisplayRootNode.Returns(true); + testTreeListener.IsSelectable.Returns(false); + testTreeListener.Title.Returns("Test Tree"); + + var testTreeData = new[] { + new TestTreeData { + Path = "Folder\\test.txt" + }, + new TestTreeData { + Path = "Folder\\test.txt.meta" + } + }; + testTree.Load(testTreeData); + + testTreeListener.Received(1).OnClear(); + testTreeListener.Received(1).SelectedNode = null; + + testTreeListener.Received(4).CreateTreeNode(Args.String, Args.String, Args.Int, Args.Bool, Args.Bool, Args.Bool, Args.Bool, Args.Bool, Arg.Any()); + testTreeListener.Received(4).SetNodeIcon(Arg.Any()); + + testTree.CreatedTreeNodes.ShouldAllBeEquivalentTo(new[] { + new TestTreeNode { + Path = "Test Tree", + Label = "Test Tree", + IsFolder = true + }, + new TestTreeNode { + Path = "Folder", + Label = "Folder", + Level = 1, + IsFolder = true + }, + new TestTreeNode { + Path = "Folder\\test.txt", + Label = "test.txt", + Level = 2, + TreeData = testTreeData[0] + }, + new TestTreeNode { + Path = "Folder\\test.txt.meta", + Label = "test.txt.meta", + Level = 2, + TreeData = testTreeData[1] + } + }); + } + [Test] public void ShouldPopulateTreeWithSingleEntryInDeepPath() { From 56bc1047770ce5bc03a98a4c77c0c7178ec0e93b Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 18 Dec 2017 15:26:46 -0500 Subject: [PATCH 0005/1008] Completing functionality to nest meta files --- src/GitHub.Api/UI/TreeBase.cs | 59 +++++++++++-- .../GitHub.Unity/UI/ChangesTreeControl.cs | 5 ++ .../Editor/GitHub.Unity/UI/TreeControl.cs | 5 ++ src/tests/UnitTests/SetUpFixture.cs | 4 +- src/tests/UnitTests/UI/TreeBaseTests.cs | 87 +++++++++++++++++-- 5 files changed, 142 insertions(+), 18 deletions(-) diff --git a/src/GitHub.Api/UI/TreeBase.cs b/src/GitHub.Api/UI/TreeBase.cs index 5f581b915..93a1d0014 100644 --- a/src/GitHub.Api/UI/TreeBase.cs +++ b/src/GitHub.Api/UI/TreeBase.cs @@ -60,22 +60,38 @@ public void Load(IEnumerable treeDatas) var folders = new HashSet(); + TNode lastAddedNode = null; foreach (var treeData in treeDatas) { var parts = treeData.Path.Split(new[] { pathSeparator }, StringSplitOptions.None); - for (var i = 0; i < parts.Length; i++) + for (var level = 0; level < parts.Length; level++) { - var label = parts[i]; - var level = i + 1; - var nodePath = String.Join(pathSeparator, parts, 0, level); - var isFolder = i < parts.Length - 1; + var label = parts[level]; + var nodePath = String.Join(pathSeparator, parts, 0, level + 1); + var isFolder = level < parts.Length - 1; + var parentIsPromoted = false; + + if (lastAddedNode != null) + { + if (!lastAddedNode.IsFolder) + { + if (PromoteNode(lastAddedNode, label)) + { + Logger.Trace("Promoting Node Label:{0}", lastAddedNode.Label); + + parentIsPromoted = true; + lastAddedNode.IsContainer = true; + } + } + } + var alreadyExists = folders.Contains(nodePath); if (!alreadyExists) { var nodeIsHidden = false; if (hideChildren) { - if (level <= hideChildrenBelowLevel) + if (level + 1 <= hideChildrenBelowLevel) { hideChildren = false; } @@ -101,7 +117,7 @@ public void Load(IEnumerable treeDatas) if (!hideChildren) { hideChildren = true; - hideChildrenBelowLevel = level; + hideChildrenBelowLevel = level + 1; } } } @@ -113,7 +129,8 @@ public void Load(IEnumerable treeDatas) } isSelected = selectedNodePath != null && nodePath == selectedNodePath; - AddNode(nodePath, label, i + displayRootLevel, isFolder, isActive, nodeIsHidden, + + lastAddedNode = AddNode(nodePath, label, level + displayRootLevel + (parentIsPromoted ? 1 : 0), isFolder, isActive, nodeIsHidden, nodeIsCollapsed, isSelected, isChecked, treeNodeTreeData, false); } } @@ -151,6 +168,27 @@ public void Load(IEnumerable treeDatas) } } + protected bool PromoteNode(TNode previouslyAddedNode, string nextLabel) + { + if (!PromoteMetaFiles) + { + return false; + } + + if (previouslyAddedNode == null) + { + return false; + } + + if (!nextLabel.EndsWith(".meta")) + { + return false; + } + + var substring = nextLabel.Substring(0, nextLabel.Length - 5); + return previouslyAddedNode.Label == substring; + } + public void SetCheckStateOnAll(bool isChecked) { var nodeCheckState = isChecked ? CheckState.Checked : CheckState.Empty; @@ -175,7 +213,7 @@ public void SetCheckStateOnAll(bool isChecked) protected abstract IEnumerable GetCollapsedFolders(); - protected void AddNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, bool isSelected, bool isChecked, TData? treeData, bool isContainer) + protected TNode AddNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, bool isSelected, bool isChecked, TData? treeData, bool isContainer) { var node = CreateTreeNode(path, label, level, isFolder, isActive, isHidden, isCollapsed, isChecked, treeData, isContainer); @@ -186,6 +224,8 @@ protected void AddNode(string path, string label, int level, bool isFolder, bool { SelectedNode = node; } + + return node; } protected void Clear() @@ -370,5 +410,6 @@ private void ToggleParentFoldersChecked(int idx, TNode node, bool isChecked) public abstract bool IsSelectable { get; set; } public abstract bool IsCheckable { get; set; } public abstract string PathSeparator { get; set; } + protected abstract bool PromoteMetaFiles { get; } } } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs index 930e84c1b..9ffe075c1 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs @@ -85,6 +85,11 @@ public override string PathSeparator set { pathSeparator = value; } } + protected override bool PromoteMetaFiles + { + get { return true; } + } + public override ChangesTreeNode SelectedNode { get diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/TreeControl.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/TreeControl.cs index 9cdcc8b31..c70cad6c9 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/TreeControl.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/TreeControl.cs @@ -589,6 +589,11 @@ public override string PathSeparator set { pathSeparator = value; } } + protected override bool PromoteMetaFiles + { + get { return false; } + } + public override TreeNode SelectedNode { get diff --git a/src/tests/UnitTests/SetUpFixture.cs b/src/tests/UnitTests/SetUpFixture.cs index 8b683ff0e..4d026d34e 100644 --- a/src/tests/UnitTests/SetUpFixture.cs +++ b/src/tests/UnitTests/SetUpFixture.cs @@ -13,8 +13,8 @@ public void SetUp() Logging.TracingEnabled = true; Logging.LogAdapter = new MultipleLogAdapter( - new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-unit-tests.log") - //, new ConsoleLogAdapter() + new FileLogAdapter($"..\\{DateTime.UtcNow:yyyyMMddHHmmss}-unit-tests.log") + , new ConsoleLogAdapter() ); } } diff --git a/src/tests/UnitTests/UI/TreeBaseTests.cs b/src/tests/UnitTests/UI/TreeBaseTests.cs index 38f62946b..1c76b95e0 100644 --- a/src/tests/UnitTests/UI/TreeBaseTests.cs +++ b/src/tests/UnitTests/UI/TreeBaseTests.cs @@ -59,6 +59,7 @@ void CreateTreeNode(string path, string label, int level, bool isFolder, bool is bool IsSelectable { get; set; } bool IsCheckable { get; set; } string PathSeparator { get; set; } + bool PromoteMetaFiles { get; set; } } public class TestTree : TreeBase @@ -295,6 +296,18 @@ public override string PathSeparator TestTreeListener.PathSeparator = value; } } + + protected override bool PromoteMetaFiles + { + get + { + if (traceLogging) + { + Logger.Trace("Property Get PromoteMetaFiles"); + } + return TestTreeListener.PromoteMetaFiles; + } + } } [TestFixture] @@ -548,13 +561,14 @@ public void ShouldPopulateTreeWithSingleEntryWithMetaInPath() testTreeListener.DisplayRootNode.Returns(true); testTreeListener.IsSelectable.Returns(false); testTreeListener.Title.Returns("Test Tree"); + testTreeListener.PromoteMetaFiles.Returns(true); var testTreeData = new[] { new TestTreeData { - Path = "Folder\\test.txt" + Path = "Folder\\Default Scene.unity" }, new TestTreeData { - Path = "Folder\\test.txt.meta" + Path = "Folder\\Default Scene.unity.meta" } }; testTree.Load(testTreeData); @@ -578,14 +592,73 @@ public void ShouldPopulateTreeWithSingleEntryWithMetaInPath() IsFolder = true }, new TestTreeNode { - Path = "Folder\\test.txt", - Label = "test.txt", + Path = "Folder\\Default Scene.unity", + Label = "Default Scene.unity", Level = 2, - TreeData = testTreeData[0] + TreeData = testTreeData[0], + IsContainer = true + }, + new TestTreeNode { + Path = "Folder\\Default Scene.unity.meta", + Label = "Default Scene.unity.meta", + Level = 3, + TreeData = testTreeData[1] + } + }); + } + [Test] + public void ShouldPopulateTreeWithSingleEntryWithNonPromotedMetaInPath() + { + var testTree = new TestTree(true); + var testTreeListener = testTree.TestTreeListener; + + testTreeListener.GetCollapsedFolders().Returns(new string[0]); + testTreeListener.SelectedNode.Returns((TestTreeNode)null); + testTreeListener.GetCheckedFiles().Returns(new string[0]); + testTreeListener.Nodes.Returns(new List()); + testTreeListener.PathSeparator.Returns(@"\"); + testTreeListener.DisplayRootNode.Returns(true); + testTreeListener.IsSelectable.Returns(false); + testTreeListener.Title.Returns("Test Tree"); + testTreeListener.PromoteMetaFiles.Returns(true); + + var testTreeData = new[] { + new TestTreeData { + Path = "Folder\\Default Scene.unity" + }, + new TestTreeData { + Path = "Folder\\Default Scene2.unity.meta" + } + }; + testTree.Load(testTreeData); + + testTreeListener.Received(1).OnClear(); + testTreeListener.Received(1).SelectedNode = null; + + testTreeListener.Received(4).CreateTreeNode(Args.String, Args.String, Args.Int, Args.Bool, Args.Bool, Args.Bool, Args.Bool, Args.Bool, Arg.Any()); + testTreeListener.Received(4).SetNodeIcon(Arg.Any()); + + testTree.CreatedTreeNodes.ShouldAllBeEquivalentTo(new[] { + new TestTreeNode { + Path = "Test Tree", + Label = "Test Tree", + IsFolder = true + }, + new TestTreeNode { + Path = "Folder", + Label = "Folder", + Level = 1, + IsFolder = true + }, + new TestTreeNode { + Path = "Folder\\Default Scene.unity", + Label = "Default Scene.unity", + Level = 2, + TreeData = testTreeData[0], }, new TestTreeNode { - Path = "Folder\\test.txt.meta", - Label = "test.txt.meta", + Path = "Folder\\Default Scene2.unity.meta", + Label = "Default Scene2.unity.meta", Level = 2, TreeData = testTreeData[1] } From 7c10c359820d3da97c10368bc278cd2ffd4b23e1 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 19 Dec 2017 11:07:06 -0500 Subject: [PATCH 0006/1008] Initial draft of a download task --- src/GitHub.Api/GitHub.Api.csproj | 1 + src/GitHub.Api/IO/FileSystem.cs | 5 + src/GitHub.Api/IO/IFileSystem.cs | 1 + src/GitHub.Api/IO/NiceIO.cs | 6 + src/GitHub.Api/Tasks/DownloadTask.cs | 238 ++++++++++++++++++ .../Download/DownloadTaskTests.cs | 42 ++++ 6 files changed, 293 insertions(+) create mode 100644 src/GitHub.Api/Tasks/DownloadTask.cs create mode 100644 src/tests/IntegrationTests/Download/DownloadTaskTests.cs diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 337412647..85382dd72 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -139,6 +139,7 @@ + diff --git a/src/GitHub.Api/IO/FileSystem.cs b/src/GitHub.Api/IO/FileSystem.cs index 4c9920da3..fc3d7a11b 100644 --- a/src/GitHub.Api/IO/FileSystem.cs +++ b/src/GitHub.Api/IO/FileSystem.cs @@ -167,6 +167,11 @@ public void WriteAllText(string path, string contents, Encoding encoding) File.WriteAllText(path, contents, encoding); } + public byte[] ReadAllBytes(string path) + { + return File.ReadAllBytes(path); + } + public string ReadAllText(string path) { return File.ReadAllText(path); diff --git a/src/GitHub.Api/IO/IFileSystem.cs b/src/GitHub.Api/IO/IFileSystem.cs index f2e5d225e..7c300e56e 100644 --- a/src/GitHub.Api/IO/IFileSystem.cs +++ b/src/GitHub.Api/IO/IFileSystem.cs @@ -41,5 +41,6 @@ public interface IFileSystem char DirectorySeparatorChar { get; } bool ExistingPathIsDirectory(string path); void SetCurrentDirectory(string currentDirectory); + byte[] ReadAllBytes(string path); } } \ No newline at end of file diff --git a/src/GitHub.Api/IO/NiceIO.cs b/src/GitHub.Api/IO/NiceIO.cs index 0b10a5f0a..ef6b91247 100644 --- a/src/GitHub.Api/IO/NiceIO.cs +++ b/src/GitHub.Api/IO/NiceIO.cs @@ -907,6 +907,12 @@ public NPath WriteAllText(string contents, Encoding encoding) return this; } + public byte[] ReadAllBytes() + { + ThrowIfRelative(); + return FileSystem.ReadAllBytes(ToString()); + } + public string ReadAllText() { ThrowIfRelative(); diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs new file mode 100644 index 000000000..15f974c2d --- /dev/null +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -0,0 +1,238 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Threading; + +namespace GitHub.Unity +{ + public class Utils + { + public static bool Copy(Stream source, Stream destination, int chunkSize) + { + return Copy(source, destination, chunkSize, 0, null, 1000); + } + + public static bool Copy(Stream source, Stream destination, int chunkSize, long totalSize, + Func progress, int progressUpdateRate) + { + byte[] buffer = new byte[chunkSize]; + int bytesRead = 0; + long totalRead = 0; + float averageSpeed = -1f; + float lastSpeed = 0f; + float smoothing = 0.005f; + long readLastSecond = 0; + long timeToFinish = 0; + Stopwatch watch = null; + bool success = true; + + bool trackProgress = totalSize > 0 && progress != null; + if (trackProgress) + watch = new Stopwatch(); + + do + { + if (trackProgress) + watch.Start(); + + bytesRead = source.Read(buffer, 0, chunkSize); + + if (trackProgress) + watch.Stop(); + + totalRead += bytesRead; + + if (bytesRead > 0) + { + destination.Write(buffer, 0, bytesRead); + if (trackProgress) + { + readLastSecond += bytesRead; + if (watch.ElapsedMilliseconds >= progressUpdateRate || totalRead == totalSize) + { + watch.Reset(); + lastSpeed = readLastSecond; + readLastSecond = 0; + averageSpeed = averageSpeed < 0f + ? lastSpeed + : smoothing * lastSpeed + (1f - smoothing) * averageSpeed; + timeToFinish = Math.Max(1L, + (long)((totalSize - totalRead) / (averageSpeed / progressUpdateRate))); + + if (!progress(totalRead, timeToFinish)) + break; + } + } + } + } while (bytesRead > 0); + + if (totalRead > 0) + destination.Flush(); + + return success; + } + } + + public class DownloadDetails + { + public string Url { get; } + public string Destination { get; } + public bool Restart { get; } + public string Md5Sum { get; } + + public DownloadDetails(string url, string destination, bool restart = false, string md5sum = null) + { + Url = url; + Restart = restart; + Destination = destination; + Md5Sum = md5sum; + } + } + + public class DownloadResult + { + + } + + public static class WebRequestExtensions + { + public static WebResponse GetResponseWithoutException(this WebRequest request) + { + try + { + return request.GetResponse(); + } + catch (WebException e) + { + return e.Response; + } + } + } + + class DownloadTask: TaskBase + { + private readonly DownloadDetails downloadDetails; + private long bytes; + private WebRequest request; + + public float Progress { get; set; } + + public DownloadTask(CancellationToken token, DownloadDetails downloadDetails) + : base(token) + { + this.downloadDetails = downloadDetails; + Name = "DownloadTask"; + } + + protected override DownloadResult RunWithReturn(bool success) + { + DownloadResult result = base.RunWithReturn(success); + + RaiseOnStart(); + + try + { + Logger.Trace("Downloading"); + + InitializeDownload(); + RunDownload(); + + Logger.Trace("Downloaded"); + } + catch (Exception ex) + { + Errors = ex.Message; + if (!RaiseFaultHandlers(ex)) + throw; + } + finally + { + RaiseOnEnd(result); + } + + return result; + } + + protected virtual void UpdateProgress(float progress) + { + Progress = progress; + } + + public bool RunDownload() + { + if (Restarted && bytes > 0) + Logger.Trace($"Resuming download of {Url} to {Destination}"); + else + Logger.Trace($"Downloading {Url} to {Destination}"); + + using (WebResponse response = request.GetResponseWithoutException()) + { + if (response == null) + return false; + + else if (Restarted && bytes > 0 && response is HttpWebResponse) + { + if ((int)(((HttpWebResponse)response).StatusCode) == 416) + { + UpdateProgress(1); + return true; + } + else if ((int)(((HttpWebResponse)response).StatusCode) != 200) + { + return false; + } + } + + long respSize = response.ContentLength; + if (Restarted && bytes > 0) + { + UpdateProgress(bytes / respSize); + if (bytes == respSize) + return true; + } + + using (Stream rStream = response.GetResponseStream()) + { + using (Stream localStream = new FileStream(Destination, FileMode.Append)) + { + if (Token.IsCancellationRequested) + return false; + + return Utils.Copy(rStream, localStream, 8192, respSize, null, 100); + } + } + } + } + + public bool Restarted => downloadDetails.Restart; + + private string Url => downloadDetails.Url; + + private string Destination => downloadDetails.Destination; + + private void InitializeDownload() + { + if (Restarted) + { + var fi = new FileInfo(Destination); + if (fi.Exists && fi.Length > 0) + bytes = fi.Length; + else if (fi.Length == 0) + fi.Delete(); + } + + request = WebRequest.Create(Url); + if (request is HttpWebRequest) + { + //((HttpWebRequest)request).UserAgent = "Unity PackageManager v" + PackageManager.Instance.Version; + + if (bytes > 0) + ((HttpWebRequest)request).AddRange((int)bytes); // TODO: fix classlibs to take long overloads + } + + request.Method = "GET"; + request.Timeout = 3000; + } + } +} diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs new file mode 100644 index 000000000..999d13640 --- /dev/null +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -0,0 +1,42 @@ +using System; +using System.Security.Cryptography; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using GitHub.Unity; +using NUnit.Framework; + +namespace IntegrationTests.Download +{ + [TestFixture] + class DownloadTaskTests: BaseTaskManagerTest + { + private const string TestDownload = "http://ipv4.download.thinkbroadband.com/5MB.zip"; + private const string TestDownloadMD5 = "b3215c06647bc550406a9c8ccc378756"; + + [Test] + public async Task Blah() + { + InitializeTaskManager(); + + var downloadPath = TestBasePath.Combine("5MB.zip"); + var downloadDetails = new DownloadDetails(TestDownload, downloadPath, false, TestDownloadMD5); + + var downloadTask = new DownloadTask(CancellationToken.None, downloadDetails); + var downloadResult = await downloadTask.StartAwait(); + + var resultBytes = downloadPath.ReadAllBytes(); + + string computedHash; + using (var md5 = MD5.Create()) + { + var computedHashBytes = md5.ComputeHash(resultBytes); + computedHash = BitConverter.ToString(computedHashBytes) + .ToLower() + .Replace("-", string.Empty); + } + + computedHash.Should().Be(TestDownloadMD5); + } + } +} From 3165e562a433fd8cfd915255cc2e3da2b6f517a3 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 19 Dec 2017 11:53:06 -0500 Subject: [PATCH 0007/1008] Initial attempt at a download task --- src/GitHub.Api/Tasks/DownloadTask.cs | 44 +++++++------------ .../IntegrationTests/BaseIntegrationTest.cs | 36 +++++++-------- .../Download/DownloadTaskTests.cs | 40 +++++++++++------ .../IntegrationTests/IntegrationTests.csproj | 1 + 4 files changed, 60 insertions(+), 61 deletions(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 15f974c2d..882db57e5 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -74,22 +74,6 @@ public static bool Copy(Stream source, Stream destination, int chunkSize, long t } } - public class DownloadDetails - { - public string Url { get; } - public string Destination { get; } - public bool Restart { get; } - public string Md5Sum { get; } - - public DownloadDetails(string url, string destination, bool restart = false, string md5sum = null) - { - Url = url; - Restart = restart; - Destination = destination; - Md5Sum = md5sum; - } - } - public class DownloadResult { @@ -112,16 +96,17 @@ public static WebResponse GetResponseWithoutException(this WebRequest request) class DownloadTask: TaskBase { - private readonly DownloadDetails downloadDetails; private long bytes; private WebRequest request; + private bool restarted; public float Progress { get; set; } - public DownloadTask(CancellationToken token, DownloadDetails downloadDetails) + public DownloadTask(CancellationToken token, string url, string destination) : base(token) { - this.downloadDetails = downloadDetails; + Url = url; + Destination = destination; Name = "DownloadTask"; } @@ -161,7 +146,7 @@ protected virtual void UpdateProgress(float progress) public bool RunDownload() { - if (Restarted && bytes > 0) + if (restarted && bytes > 0) Logger.Trace($"Resuming download of {Url} to {Destination}"); else Logger.Trace($"Downloading {Url} to {Destination}"); @@ -171,7 +156,7 @@ public bool RunDownload() if (response == null) return false; - else if (Restarted && bytes > 0 && response is HttpWebResponse) + else if (restarted && bytes > 0 && response is HttpWebResponse) { if ((int)(((HttpWebResponse)response).StatusCode) == 416) { @@ -185,7 +170,7 @@ public bool RunDownload() } long respSize = response.ContentLength; - if (Restarted && bytes > 0) + if (restarted && bytes > 0) { UpdateProgress(bytes / respSize); if (bytes == respSize) @@ -205,19 +190,20 @@ public bool RunDownload() } } - public bool Restarted => downloadDetails.Restart; + protected string Url { get; } - private string Url => downloadDetails.Url; - - private string Destination => downloadDetails.Destination; + protected string Destination { get; } private void InitializeDownload() { - if (Restarted) + var fi = new FileInfo(Destination); + if (fi.Exists) { - var fi = new FileInfo(Destination); - if (fi.Exists && fi.Length > 0) + if (fi.Length > 0) + { bytes = fi.Length; + restarted = true; + } else if (fi.Length == 0) fi.Delete(); } diff --git a/src/tests/IntegrationTests/BaseIntegrationTest.cs b/src/tests/IntegrationTests/BaseIntegrationTest.cs index fce868c0b..f8f6a2acd 100644 --- a/src/tests/IntegrationTests/BaseIntegrationTest.cs +++ b/src/tests/IntegrationTests/BaseIntegrationTest.cs @@ -41,24 +41,24 @@ public virtual void OnSetup() [TearDown] public virtual void OnTearDown() { - TaskManager.Instance?.Dispose(); - Logger.Debug("Deleting TestBasePath: {0}", TestBasePath.ToString()); - for (var i = 0; i < 5; i++) - { - try - { - TestBasePath.Delete(); - break; - } - catch (Exception) - { - Thread.Sleep(100); - } - } - if (TestBasePath.Exists()) - Logger.Warning("Error deleting TestBasePath: {0}", TestBasePath.ToString()); - - NPath.FileSystem = null; +// TaskManager.Instance?.Dispose(); +// Logger.Debug("Deleting TestBasePath: {0}", TestBasePath.ToString()); +// for (var i = 0; i < 5; i++) +// { +// try +// { +// TestBasePath.Delete(); +// break; +// } +// catch (Exception) +// { +// Thread.Sleep(100); +// } +// } +// if (TestBasePath.Exists()) +// Logger.Warning("Error deleting TestBasePath: {0}", TestBasePath.ToString()); +// +// NPath.FileSystem = null; } } } \ No newline at end of file diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 999d13640..aef7717fe 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; @@ -15,28 +16,39 @@ class DownloadTaskTests: BaseTaskManagerTest private const string TestDownloadMD5 = "b3215c06647bc550406a9c8ccc378756"; [Test] - public async Task Blah() + public async Task TestDownloadTask() { InitializeTaskManager(); + var fileSystem = new FileSystem(); + var downloadPath = TestBasePath.Combine("5MB.zip"); - var downloadDetails = new DownloadDetails(TestDownload, downloadPath, false, TestDownloadMD5); + var downloadHalfPath = TestBasePath.Combine("5MB-split.zip"); + + var downloadTask = new DownloadTask(CancellationToken.None, TestDownload, downloadPath); + await downloadTask.StartAwait(); + + var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); + Logger.Trace("File size {0} bytes", downloadPathBytes.Length); + + var computedHash = fileSystem.CalculateMD5(downloadPath); + computedHash.Should().Be(TestDownloadMD5.ToUpperInvariant()); + + var takeCount = downloadPathBytes.Length / 2; + + Logger.Trace("Cutting {0} Bytes", downloadPathBytes.Length - takeCount); - var downloadTask = new DownloadTask(CancellationToken.None, downloadDetails); - var downloadResult = await downloadTask.StartAwait(); + var cutDownloadPathBytes = downloadPathBytes.Take(takeCount).ToArray(); + fileSystem.WriteAllBytes(downloadHalfPath, cutDownloadPathBytes); - var resultBytes = downloadPath.ReadAllBytes(); + downloadTask = new DownloadTask(CancellationToken.None, TestDownload, downloadHalfPath); + await downloadTask.StartAwait(); - string computedHash; - using (var md5 = MD5.Create()) - { - var computedHashBytes = md5.ComputeHash(resultBytes); - computedHash = BitConverter.ToString(computedHashBytes) - .ToLower() - .Replace("-", string.Empty); - } + var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadHalfPath); + Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); - computedHash.Should().Be(TestDownloadMD5); + computedHash = fileSystem.CalculateMD5(downloadHalfPath); + computedHash.Should().Be(TestDownloadMD5.ToUpperInvariant()); } } } diff --git a/src/tests/IntegrationTests/IntegrationTests.csproj b/src/tests/IntegrationTests/IntegrationTests.csproj index 4c8d3da01..3b5b8cb08 100644 --- a/src/tests/IntegrationTests/IntegrationTests.csproj +++ b/src/tests/IntegrationTests/IntegrationTests.csproj @@ -74,6 +74,7 @@ + From 9c47ff7c386d532da0ed7415627d262d3499c7ea Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 19 Dec 2017 15:28:44 -0500 Subject: [PATCH 0008/1008] Fixing download of partial files --- src/GitHub.Api/Tasks/DownloadTask.cs | 12 +++++++----- .../IntegrationTests/Download/DownloadTaskTests.cs | 5 +++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 882db57e5..415d324e4 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -156,14 +156,16 @@ public bool RunDownload() if (response == null) return false; - else if (restarted && bytes > 0 && response is HttpWebResponse) + if (restarted && bytes > 0 && response is HttpWebResponse) { - if ((int)(((HttpWebResponse)response).StatusCode) == 416) + var httpStatusCode = ((HttpWebResponse)response).StatusCode; + if (httpStatusCode == HttpStatusCode.RequestedRangeNotSatisfiable) { UpdateProgress(1); return true; } - else if ((int)(((HttpWebResponse)response).StatusCode) != 200) + + if (!(httpStatusCode == HttpStatusCode.OK || httpStatusCode == HttpStatusCode.PartialContent)) { return false; } @@ -173,8 +175,6 @@ public bool RunDownload() if (restarted && bytes > 0) { UpdateProgress(bytes / respSize); - if (bytes == respSize) - return true; } using (Stream rStream = response.GetResponseStream()) @@ -205,7 +205,9 @@ private void InitializeDownload() restarted = true; } else if (fi.Length == 0) + { fi.Delete(); + } } request = WebRequest.Create(Url); diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index aef7717fe..0fc68958c 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -34,9 +34,10 @@ public async Task TestDownloadTask() var computedHash = fileSystem.CalculateMD5(downloadPath); computedHash.Should().Be(TestDownloadMD5.ToUpperInvariant()); - var takeCount = downloadPathBytes.Length / 2; + var random = new Random(); + var takeCount = random.Next(downloadPathBytes.Length); - Logger.Trace("Cutting {0} Bytes", downloadPathBytes.Length - takeCount); + Logger.Trace("Cutting the first {0} Bytes", downloadPathBytes.Length - takeCount); var cutDownloadPathBytes = downloadPathBytes.Take(takeCount).ToArray(); fileSystem.WriteAllBytes(downloadHalfPath, cutDownloadPathBytes); From 3b3debfca5381f73892c2153f04ce4644879ac9b Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 19 Dec 2017 15:30:04 -0500 Subject: [PATCH 0009/1008] Renaming some variables --- src/GitHub.Api/Tasks/DownloadTask.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 415d324e4..e8c370007 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -171,20 +171,20 @@ public bool RunDownload() } } - long respSize = response.ContentLength; + var responseLength = response.ContentLength; if (restarted && bytes > 0) { - UpdateProgress(bytes / respSize); + UpdateProgress(bytes / responseLength); } - using (Stream rStream = response.GetResponseStream()) + using (var responseStream = response.GetResponseStream()) { - using (Stream localStream = new FileStream(Destination, FileMode.Append)) + using (Stream destinationStream = new FileStream(Destination, FileMode.Append)) { if (Token.IsCancellationRequested) return false; - return Utils.Copy(rStream, localStream, 8192, respSize, null, 100); + return Utils.Copy(responseStream, destinationStream, 8192, responseLength, null, 100); } } } From 668661d304c7e2d10583be1234905f9a39013c99 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 19 Dec 2017 16:03:17 -0500 Subject: [PATCH 0010/1008] Inline some methods --- src/GitHub.Api/Tasks/DownloadTask.cs | 93 ++++++++++++++-------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index e8c370007..6d301d0fe 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -97,7 +97,7 @@ public static WebResponse GetResponseWithoutException(this WebRequest request) class DownloadTask: TaskBase { private long bytes; - private WebRequest request; + private WebRequest webRequest; private bool restarted; public float Progress { get; set; } @@ -119,8 +119,6 @@ protected override DownloadResult RunWithReturn(bool success) try { Logger.Trace("Downloading"); - - InitializeDownload(); RunDownload(); Logger.Trace("Downloaded"); @@ -146,38 +144,70 @@ protected virtual void UpdateProgress(float progress) public bool RunDownload() { + var fileInfo = new FileInfo(Destination); + if (fileInfo.Exists) + { + if (fileInfo.Length > 0) + { + bytes = fileInfo.Length; + restarted = true; + } + else if (fileInfo.Length == 0) + { + fileInfo.Delete(); + } + } + + webRequest = WebRequest.Create(Url); + var httpWebRequest = webRequest as HttpWebRequest; + if (httpWebRequest != null) + { + if (bytes > 0) + { + // TODO: fix classlibs to take long overloads + httpWebRequest.AddRange((int)bytes); + } + } + + webRequest.Method = "GET"; + webRequest.Timeout = 3000; + if (restarted && bytes > 0) Logger.Trace($"Resuming download of {Url} to {Destination}"); else Logger.Trace($"Downloading {Url} to {Destination}"); - using (WebResponse response = request.GetResponseWithoutException()) + using (var webResponse = webRequest.GetResponseWithoutException()) { - if (response == null) + if (webResponse == null) return false; - if (restarted && bytes > 0 && response is HttpWebResponse) + if (restarted && bytes > 0) { - var httpStatusCode = ((HttpWebResponse)response).StatusCode; - if (httpStatusCode == HttpStatusCode.RequestedRangeNotSatisfiable) + var httpWebResponse = webResponse as HttpWebResponse; + if (httpWebResponse != null) { - UpdateProgress(1); - return true; - } + var httpStatusCode = httpWebResponse.StatusCode; + if (httpStatusCode == HttpStatusCode.RequestedRangeNotSatisfiable) + { + UpdateProgress(1); + return true; + } - if (!(httpStatusCode == HttpStatusCode.OK || httpStatusCode == HttpStatusCode.PartialContent)) - { - return false; + if (!(httpStatusCode == HttpStatusCode.OK || httpStatusCode == HttpStatusCode.PartialContent)) + { + return false; + } } } - var responseLength = response.ContentLength; + var responseLength = webResponse.ContentLength; if (restarted && bytes > 0) { - UpdateProgress(bytes / responseLength); + UpdateProgress(bytes / (float) responseLength); } - using (var responseStream = response.GetResponseStream()) + using (var responseStream = webResponse.GetResponseStream()) { using (Stream destinationStream = new FileStream(Destination, FileMode.Append)) { @@ -193,34 +223,5 @@ public bool RunDownload() protected string Url { get; } protected string Destination { get; } - - private void InitializeDownload() - { - var fi = new FileInfo(Destination); - if (fi.Exists) - { - if (fi.Length > 0) - { - bytes = fi.Length; - restarted = true; - } - else if (fi.Length == 0) - { - fi.Delete(); - } - } - - request = WebRequest.Create(Url); - if (request is HttpWebRequest) - { - //((HttpWebRequest)request).UserAgent = "Unity PackageManager v" + PackageManager.Instance.Version; - - if (bytes > 0) - ((HttpWebRequest)request).AddRange((int)bytes); // TODO: fix classlibs to take long overloads - } - - request.Method = "GET"; - request.Timeout = 3000; - } } } From 8e07c418bf7f3e1c25941b7542c7bff189a34899 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 19 Dec 2017 16:24:25 -0500 Subject: [PATCH 0011/1008] Uncommenting delete of integration test folder --- .../IntegrationTests/BaseIntegrationTest.cs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/tests/IntegrationTests/BaseIntegrationTest.cs b/src/tests/IntegrationTests/BaseIntegrationTest.cs index f8f6a2acd..fce868c0b 100644 --- a/src/tests/IntegrationTests/BaseIntegrationTest.cs +++ b/src/tests/IntegrationTests/BaseIntegrationTest.cs @@ -41,24 +41,24 @@ public virtual void OnSetup() [TearDown] public virtual void OnTearDown() { -// TaskManager.Instance?.Dispose(); -// Logger.Debug("Deleting TestBasePath: {0}", TestBasePath.ToString()); -// for (var i = 0; i < 5; i++) -// { -// try -// { -// TestBasePath.Delete(); -// break; -// } -// catch (Exception) -// { -// Thread.Sleep(100); -// } -// } -// if (TestBasePath.Exists()) -// Logger.Warning("Error deleting TestBasePath: {0}", TestBasePath.ToString()); -// -// NPath.FileSystem = null; + TaskManager.Instance?.Dispose(); + Logger.Debug("Deleting TestBasePath: {0}", TestBasePath.ToString()); + for (var i = 0; i < 5; i++) + { + try + { + TestBasePath.Delete(); + break; + } + catch (Exception) + { + Thread.Sleep(100); + } + } + if (TestBasePath.Exists()) + Logger.Warning("Error deleting TestBasePath: {0}", TestBasePath.ToString()); + + NPath.FileSystem = null; } } } \ No newline at end of file From 5298102902877fa1a36c0b426e8325b03a393723 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 19 Dec 2017 16:25:40 -0500 Subject: [PATCH 0012/1008] Using DownloadResult and calculating MD5 --- src/GitHub.Api/IO/FileSystem.cs | 11 +++++ src/GitHub.Api/IO/IFileSystem.cs | 2 + src/GitHub.Api/Tasks/DownloadTask.cs | 44 ++++++++++++------- .../Download/DownloadTaskTests.cs | 14 +++--- 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/GitHub.Api/IO/FileSystem.cs b/src/GitHub.Api/IO/FileSystem.cs index fc3d7a11b..297d7c1bf 100644 --- a/src/GitHub.Api/IO/FileSystem.cs +++ b/src/GitHub.Api/IO/FileSystem.cs @@ -34,6 +34,12 @@ public bool FileExists(string filename) return File.Exists(filename); } + public long FileLength(string path) + { + var fileInfo = new FileInfo(path); + return fileInfo.Length; + } + public IEnumerable GetDirectories(string path) { return Directory.GetDirectories(path); @@ -206,5 +212,10 @@ public Stream OpenRead(string path) { return File.OpenRead(path); } + + public Stream OpenWrite(string path, FileMode mode) + { + return new FileStream(path, mode); + } } } diff --git a/src/GitHub.Api/IO/IFileSystem.cs b/src/GitHub.Api/IO/IFileSystem.cs index 7c300e56e..6e78038f6 100644 --- a/src/GitHub.Api/IO/IFileSystem.cs +++ b/src/GitHub.Api/IO/IFileSystem.cs @@ -7,6 +7,7 @@ namespace GitHub.Unity public interface IFileSystem { bool FileExists(string path); + long FileLength(string path); string Combine(string path1, string path2); string Combine(string path1, string path2, string path3); string GetFullPath(string path); @@ -37,6 +38,7 @@ public interface IFileSystem string ReadAllText(string path); string ReadAllText(string path, Encoding encoding); Stream OpenRead(string path); + Stream OpenWrite(string path, FileMode mode); string[] ReadAllLines(string path); char DirectorySeparatorChar { get; } bool ExistingPathIsDirectory(string path); diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 6d301d0fe..159b2be61 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -76,7 +76,13 @@ public static bool Copy(Stream source, Stream destination, int chunkSize, long t public class DownloadResult { + public bool Success { get; set; } + public string Url { get; set; } + + public string Destination { get; set; } + + public string MD5Sum { get; set; } } public static class WebRequestExtensions @@ -96,15 +102,17 @@ public static WebResponse GetResponseWithoutException(this WebRequest request) class DownloadTask: TaskBase { + private IFileSystem fileSystem; private long bytes; private WebRequest webRequest; private bool restarted; public float Progress { get; set; } - public DownloadTask(CancellationToken token, string url, string destination) + public DownloadTask(CancellationToken token, IFileSystem fileSystem, string url, string destination) : base(token) { + this.fileSystem = fileSystem; Url = url; Destination = destination; Name = "DownloadTask"; @@ -112,16 +120,19 @@ public DownloadTask(CancellationToken token, string url, string destination) protected override DownloadResult RunWithReturn(bool success) { - DownloadResult result = base.RunWithReturn(success); - + base.RunWithReturn(success); + RaiseOnStart(); + var downloadResult = new DownloadResult { + Url = Url, + Destination = Destination + }; + try { - Logger.Trace("Downloading"); - RunDownload(); - - Logger.Trace("Downloaded"); + downloadResult.Success = Download(); + downloadResult.MD5Sum = fileSystem.CalculateMD5(Destination); } catch (Exception ex) { @@ -131,10 +142,10 @@ protected override DownloadResult RunWithReturn(bool success) } finally { - RaiseOnEnd(result); + RaiseOnEnd(downloadResult); } - return result; + return downloadResult; } protected virtual void UpdateProgress(float progress) @@ -142,19 +153,20 @@ protected virtual void UpdateProgress(float progress) Progress = progress; } - public bool RunDownload() + public bool Download() { - var fileInfo = new FileInfo(Destination); - if (fileInfo.Exists) + FileInfo fileInfo = new FileInfo(Destination); + if (fileSystem.FileExists(Destination)) { - if (fileInfo.Length > 0) + var fileLength = fileSystem.FileLength(Destination); + if (fileLength > 0) { bytes = fileInfo.Length; restarted = true; } - else if (fileInfo.Length == 0) + else if (fileLength == 0) { - fileInfo.Delete(); + fileSystem.FileDelete(Destination); } } @@ -209,7 +221,7 @@ public bool RunDownload() using (var responseStream = webResponse.GetResponseStream()) { - using (Stream destinationStream = new FileStream(Destination, FileMode.Append)) + using (var destinationStream = fileSystem.OpenWrite(Destination, FileMode.Append)) { if (Token.IsCancellationRequested) return false; diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 0fc68958c..2e237defe 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -25,14 +25,13 @@ public async Task TestDownloadTask() var downloadPath = TestBasePath.Combine("5MB.zip"); var downloadHalfPath = TestBasePath.Combine("5MB-split.zip"); - var downloadTask = new DownloadTask(CancellationToken.None, TestDownload, downloadPath); - await downloadTask.StartAwait(); + var downloadTask = new DownloadTask(CancellationToken.None, fileSystem, TestDownload, downloadPath); + var downloadResult = await downloadTask.StartAwait(); var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); Logger.Trace("File size {0} bytes", downloadPathBytes.Length); - var computedHash = fileSystem.CalculateMD5(downloadPath); - computedHash.Should().Be(TestDownloadMD5.ToUpperInvariant()); + downloadResult.MD5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); var random = new Random(); var takeCount = random.Next(downloadPathBytes.Length); @@ -42,14 +41,13 @@ public async Task TestDownloadTask() var cutDownloadPathBytes = downloadPathBytes.Take(takeCount).ToArray(); fileSystem.WriteAllBytes(downloadHalfPath, cutDownloadPathBytes); - downloadTask = new DownloadTask(CancellationToken.None, TestDownload, downloadHalfPath); - await downloadTask.StartAwait(); + downloadTask = new DownloadTask(CancellationToken.None, fileSystem, TestDownload, downloadHalfPath); + downloadResult = await downloadTask.StartAwait(); var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadHalfPath); Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); - computedHash = fileSystem.CalculateMD5(downloadHalfPath); - computedHash.Should().Be(TestDownloadMD5.ToUpperInvariant()); + downloadResult.MD5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); } } } From 48c1d5c1b8cbfd887618dae23c7d598638dfe535 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 19 Dec 2017 16:25:55 -0500 Subject: [PATCH 0013/1008] Adding MD5 to Resharper abbreviations --- GitHub.Unity.sln.DotSettings | 1 + 1 file changed, 1 insertion(+) diff --git a/GitHub.Unity.sln.DotSettings b/GitHub.Unity.sln.DotSettings index d4374a413..ce5e4a30b 100644 --- a/GitHub.Unity.sln.DotSettings +++ b/GitHub.Unity.sln.DotSettings @@ -335,6 +335,7 @@ </TypePattern> </Patterns> ID + MD5 SSH <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> From 3831d92bfbd9c88b043a5b879916e39159a02bf8 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 27 Dec 2017 17:57:14 -0500 Subject: [PATCH 0014/1008] Unizip Task & Test --- src/GitHub.Api/GitHub.Api.csproj | 1 + src/GitHub.Api/Installer/UnzipTask.cs | 42 ++++++++++++++++++ src/tests/IntegrationTests/UnzipTaskTests.cs | 45 ++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 src/GitHub.Api/Installer/UnzipTask.cs create mode 100644 src/tests/IntegrationTests/UnzipTaskTests.cs diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 337412647..abe84e6eb 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -117,6 +117,7 @@ + diff --git a/src/GitHub.Api/Installer/UnzipTask.cs b/src/GitHub.Api/Installer/UnzipTask.cs new file mode 100644 index 000000000..8c3fbc841 --- /dev/null +++ b/src/GitHub.Api/Installer/UnzipTask.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace GitHub.Unity +{ + class UnzipTask: TaskBase + { + protected static ILogging Logger { get; } = Logging.GetLogger(); + + private string archiveFilePath; + private string extractedPath; + private IProgress zipFileProgress; + private IProgress estimatedDurationProgress; + + public UnzipTask(CancellationToken token, string archiveFilePath, string extractedPath, IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) + : base(token) + { + this.archiveFilePath = archiveFilePath; + this.extractedPath = extractedPath; + this.zipFileProgress = zipFileProgress; + this.estimatedDurationProgress = estimatedDurationProgress; + } + + protected override void Run(bool success) + { + base.Run(success); + + UnzipArchive(); + } + + private void UnzipArchive() + { + Logger.Trace("Zip File: {0}", archiveFilePath); + Logger.Trace("Target Path: {0}", extractedPath); + + ZipHelper.ExtractZipFile(archiveFilePath, extractedPath, Token, zipFileProgress, estimatedDurationProgress); + + Logger.Trace("Completed"); + } + } +} diff --git a/src/tests/IntegrationTests/UnzipTaskTests.cs b/src/tests/IntegrationTests/UnzipTaskTests.cs new file mode 100644 index 000000000..3abc9a07b --- /dev/null +++ b/src/tests/IntegrationTests/UnzipTaskTests.cs @@ -0,0 +1,45 @@ +using System.Threading; +using System.Threading.Tasks; +using GitHub.Unity; +using Microsoft.Win32.SafeHandles; +using NSubstitute; +using NUnit.Framework; +using Rackspace.Threading; + +namespace IntegrationTests +{ + [TestFixture] + class UnzipTaskTests : BaseTaskManagerTest + { + [Test] + public void UnzipTest() + { + InitializeTaskManager(); + + var cacheContainer = Substitute.For(); + Environment = new IntegrationTestEnvironment(cacheContainer, TestBasePath, SolutionDirectory); + + var archiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", TestBasePath.Combine("gip_zip_extracted"), Environment); + + Logger.Trace("ArchiveFilePath: {0}", archiveFilePath); + Logger.Trace("TestBasePath: {0}", TestBasePath); + + var extractedPath = TestBasePath.Combine("git_zip_extracted"); + extractedPath.CreateDirectory(); + + var zipProgress = 0; + Logger.Trace("Pct Complete {0}%", zipProgress); + var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, + new Progress(zipFileProgress => { + var zipFileProgressInteger = (int) (zipFileProgress * 100); + if (zipProgress != zipFileProgressInteger) + { + zipProgress = zipFileProgressInteger; + Logger.Trace("Pct Complete {0}%", zipProgress); + } + })); + + unzipTask.Start().Wait(); + } + } +} \ No newline at end of file From c2274a50ca9ee5f37c274dcd0c3a90176dafc2ca Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 28 Dec 2017 15:32:43 -0500 Subject: [PATCH 0015/1008] Removing extra logging instance --- src/GitHub.Api/Installer/UnzipTask.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/GitHub.Api/Installer/UnzipTask.cs b/src/GitHub.Api/Installer/UnzipTask.cs index 8c3fbc841..0e7c3a16d 100644 --- a/src/GitHub.Api/Installer/UnzipTask.cs +++ b/src/GitHub.Api/Installer/UnzipTask.cs @@ -6,12 +6,10 @@ namespace GitHub.Unity { class UnzipTask: TaskBase { - protected static ILogging Logger { get; } = Logging.GetLogger(); - - private string archiveFilePath; - private string extractedPath; - private IProgress zipFileProgress; - private IProgress estimatedDurationProgress; + private readonly string archiveFilePath; + private readonly string extractedPath; + private readonly IProgress zipFileProgress; + private readonly IProgress estimatedDurationProgress; public UnzipTask(CancellationToken token, string archiveFilePath, string extractedPath, IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) : base(token) From fe52374f15fd87e7cd8f7a9bd37f45578ccad9ea Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 28 Dec 2017 15:50:49 -0500 Subject: [PATCH 0016/1008] Using a single ZipHelper instance instead of delegate --- src/GitHub.Api/Installer/GitInstaller.cs | 18 ++++++------------ src/GitHub.Api/Installer/UnzipTask.cs | 13 +++++++++++-- src/GitHub.Api/Installer/ZipHelper.cs | 15 +++++++++++++++ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index f54765298..1e7f397f9 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -18,17 +18,14 @@ class GitInstaller : IGitInstaller private readonly CancellationToken cancellationToken; private readonly IEnvironment environment; private readonly ILogging logger; - - private delegate void ExtractZipFile(string archive, string outFolder, CancellationToken cancellationToken, - IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null); - private ExtractZipFile extractCallback; + private readonly IZipHelper zipHelper; public GitInstaller(IEnvironment environment, CancellationToken cancellationToken) - : this(environment, null, cancellationToken) + : this(environment, ZipHelper.Instance, cancellationToken) { } - public GitInstaller(IEnvironment environment, IZipHelper sharpZipLibHelper, CancellationToken cancellationToken) + public GitInstaller(IEnvironment environment, IZipHelper zipHelper, CancellationToken cancellationToken) { Guard.ArgumentNotNull(environment, nameof(environment)); @@ -36,10 +33,7 @@ public GitInstaller(IEnvironment environment, IZipHelper sharpZipLibHelper, Canc this.cancellationToken = cancellationToken; this.environment = environment; - this.extractCallback = sharpZipLibHelper != null - ? (ExtractZipFile)sharpZipLibHelper.Extract - : ZipHelper.ExtractZipFile; - + this.zipHelper = zipHelper; GitInstallationPath = environment.GetSpecialFolder(Environment.SpecialFolder.LocalApplicationData) .ToNPath().Combine(ApplicationInfo.ApplicationName, PackageNameWithVersion); @@ -184,7 +178,7 @@ public Task SetupGitIfNeeded(NPath tempPath, IProgress zipFileProgr { logger.Trace("Extracting \"{0}\" to \"{1}\"", archiveFilePath, unzipPath); - extractCallback(archiveFilePath, unzipPath, cancellationToken, zipFileProgress, + zipHelper.Extract(archiveFilePath, unzipPath, cancellationToken, zipFileProgress, estimatedDurationProgress); } catch (Exception ex) @@ -249,7 +243,7 @@ public Task SetupGitLfsIfNeeded(NPath tempPath, IProgress zipFilePr { logger.Trace("Extracting \"{0}\" to \"{1}\"", archiveFilePath, unzipPath); - extractCallback(archiveFilePath, unzipPath, cancellationToken, zipFileProgress, + zipHelper.Extract(archiveFilePath, unzipPath, cancellationToken, zipFileProgress, estimatedDurationProgress); } catch (Exception ex) diff --git a/src/GitHub.Api/Installer/UnzipTask.cs b/src/GitHub.Api/Installer/UnzipTask.cs index 0e7c3a16d..7478deb6f 100644 --- a/src/GitHub.Api/Installer/UnzipTask.cs +++ b/src/GitHub.Api/Installer/UnzipTask.cs @@ -8,14 +8,23 @@ class UnzipTask: TaskBase { private readonly string archiveFilePath; private readonly string extractedPath; + private readonly IZipHelper zipHelper; private readonly IProgress zipFileProgress; private readonly IProgress estimatedDurationProgress; - public UnzipTask(CancellationToken token, string archiveFilePath, string extractedPath, IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) + public UnzipTask(CancellationToken token, string archiveFilePath, string extractedPath, + IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) : + this(token, archiveFilePath, extractedPath, ZipHelper.Instance, zipFileProgress, estimatedDurationProgress) + { + + } + + public UnzipTask(CancellationToken token, string archiveFilePath, string extractedPath, IZipHelper zipHelper, IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) : base(token) { this.archiveFilePath = archiveFilePath; this.extractedPath = extractedPath; + this.zipHelper = zipHelper; this.zipFileProgress = zipFileProgress; this.estimatedDurationProgress = estimatedDurationProgress; } @@ -32,7 +41,7 @@ private void UnzipArchive() Logger.Trace("Zip File: {0}", archiveFilePath); Logger.Trace("Target Path: {0}", extractedPath); - ZipHelper.ExtractZipFile(archiveFilePath, extractedPath, Token, zipFileProgress, estimatedDurationProgress); + zipHelper.Extract(archiveFilePath, extractedPath, Token, zipFileProgress, estimatedDurationProgress); Logger.Trace("Completed"); } diff --git a/src/GitHub.Api/Installer/ZipHelper.cs b/src/GitHub.Api/Installer/ZipHelper.cs index dc7f726ee..34701b803 100644 --- a/src/GitHub.Api/Installer/ZipHelper.cs +++ b/src/GitHub.Api/Installer/ZipHelper.cs @@ -8,6 +8,21 @@ namespace GitHub.Unity { class ZipHelper : IZipHelper { + private static IZipHelper instance; + + public static IZipHelper Instance + { + get + { + if (instance == null) + { + instance = new ZipHelper(); + } + + return instance; + } + } + public static bool Copy(Stream source, Stream destination, int chunkSize, long totalSize, Func progress, int progressUpdateRate) { From 934d2c256b554ee9601ad96320a798832704a339 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 28 Dec 2017 15:56:16 -0500 Subject: [PATCH 0017/1008] Adding functionality to md5 an entire folder --- GitHub.Unity.sln.DotSettings | 1 + .../Extensions/FileSystemExtensions.cs | 50 ++++++++++++++++++- src/GitHub.Api/IO/FileSystem.cs | 5 ++ src/GitHub.Api/IO/IFileSystem.cs | 1 + 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/GitHub.Unity.sln.DotSettings b/GitHub.Unity.sln.DotSettings index d4374a413..50b26bf2b 100644 --- a/GitHub.Unity.sln.DotSettings +++ b/GitHub.Unity.sln.DotSettings @@ -335,6 +335,7 @@ </TypePattern> </Patterns> ID + ME SSH <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> diff --git a/src/GitHub.Api/Extensions/FileSystemExtensions.cs b/src/GitHub.Api/Extensions/FileSystemExtensions.cs index 0e434dda4..8eb311f6f 100644 --- a/src/GitHub.Api/Extensions/FileSystemExtensions.cs +++ b/src/GitHub.Api/Extensions/FileSystemExtensions.cs @@ -1,4 +1,6 @@ using System; +using System.IO; +using System.Linq; using System.Security.Cryptography; using System.Text; @@ -6,7 +8,22 @@ namespace GitHub.Unity { static class FileSystemExtensions { - public static string CalculateMD5(this IFileSystem fileSystem, string file) + public static string CalculateMD5(this IFileSystem fileSystem, string path) + { + if (fileSystem.DirectoryExists(path)) + { + return fileSystem.CalculateFolderMD5(path); + } + + if (fileSystem.FileExists(path)) + { + return fileSystem.CalculateFileMD5(path); + } + + throw new ArgumentException($@"Path does not exist: ""{path}"""); + } + + public static string CalculateFileMD5(this IFileSystem fileSystem, string file) { byte[] computeHash; using (var md5 = MD5.Create()) @@ -17,7 +34,36 @@ public static string CalculateMD5(this IFileSystem fileSystem, string file) } } - return BitConverter.ToString(computeHash).Replace("-", string.Empty); + return BitConverter.ToString(computeHash).Replace("-", string.Empty).ToLower(); + } + + public static string CalculateFolderMD5(this IFileSystem fileSystem, string path) + { + //https://stackoverflow.com/questions/3625658/creating-hash-for-folder + + var filePaths = fileSystem.GetFiles(path, "*", SearchOption.AllDirectories) + .OrderBy(p => p) + .ToArray(); + + using (var md5 = MD5.Create()) + { + foreach (var filePath in filePaths) + { + // hash path + var relativeFilePath = filePath.Substring(path.Length + 1); + var pathBytes = Encoding.UTF8.GetBytes(relativeFilePath); + md5.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0); + + // hash contents + var contentBytes = File.ReadAllBytes(filePath); + md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0); + } + + //Handles empty filePaths case + md5.TransformFinalBlock(new byte[0], 0, 0); + + return BitConverter.ToString(md5.Hash).Replace("-", "").ToLower(); + } } } } \ No newline at end of file diff --git a/src/GitHub.Api/IO/FileSystem.cs b/src/GitHub.Api/IO/FileSystem.cs index 4c9920da3..fc3d7a11b 100644 --- a/src/GitHub.Api/IO/FileSystem.cs +++ b/src/GitHub.Api/IO/FileSystem.cs @@ -167,6 +167,11 @@ public void WriteAllText(string path, string contents, Encoding encoding) File.WriteAllText(path, contents, encoding); } + public byte[] ReadAllBytes(string path) + { + return File.ReadAllBytes(path); + } + public string ReadAllText(string path) { return File.ReadAllText(path); diff --git a/src/GitHub.Api/IO/IFileSystem.cs b/src/GitHub.Api/IO/IFileSystem.cs index f2e5d225e..de35e12ff 100644 --- a/src/GitHub.Api/IO/IFileSystem.cs +++ b/src/GitHub.Api/IO/IFileSystem.cs @@ -34,6 +34,7 @@ public interface IFileSystem void WriteAllText(string path, string contents); void WriteAllText(string path, string contents, Encoding encoding); void WriteAllLines(string path, string[] contents); + byte[] ReadAllBytes(string path); string ReadAllText(string path); string ReadAllText(string path, Encoding encoding); Stream OpenRead(string path); From d02475841c8c3e691b525eb7ee4db37bfa643392 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 28 Dec 2017 16:21:02 -0500 Subject: [PATCH 0018/1008] Adding functionality to asynchronously install portable git --- .../Application/ApplicationManagerBase.cs | 116 ++++--- src/GitHub.Api/Git/GitClient.cs | 76 +---- src/GitHub.Api/GitHub.Api.csproj | 4 +- src/GitHub.Api/Installer/GitInstaller.cs | 288 ------------------ src/GitHub.Api/Installer/IGitInstaller.cs | 13 - .../Installer/PortableGitInstallTask.cs | 209 +++++++++++++ src/GitHub.Api/Installer/ShortCircuitTask.cs | 32 ++ .../BaseGitEnvironmentTest.cs | 5 +- .../BasePlatformIntegrationTest.cs | 23 +- .../Events/RepositoryManagerTests.cs | 24 +- .../Events/RepositoryWatcherTests.cs | 14 +- .../{ => Git}/GitClientTests.cs | 8 +- .../IntegrationTests/Git/GitSetupTests.cs | 110 ------- .../Installer/PortableGitInstallTaskTests.cs | 36 +++ .../Installer/ShortCircuitTaskTests.cs | 71 +++++ .../{Git => }/IntegrationTestEnvironment.cs | 0 .../IntegrationTests/IntegrationTests.csproj | 8 +- .../Process/ProcessManagerIntegrationTests.cs | 12 +- 18 files changed, 478 insertions(+), 571 deletions(-) delete mode 100644 src/GitHub.Api/Installer/GitInstaller.cs delete mode 100644 src/GitHub.Api/Installer/IGitInstaller.cs create mode 100644 src/GitHub.Api/Installer/PortableGitInstallTask.cs create mode 100644 src/GitHub.Api/Installer/ShortCircuitTask.cs rename src/tests/IntegrationTests/{ => Git}/GitClientTests.cs (81%) delete mode 100644 src/tests/IntegrationTests/Git/GitSetupTests.cs create mode 100644 src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs create mode 100644 src/tests/IntegrationTests/Installer/ShortCircuitTaskTests.cs rename src/tests/IntegrationTests/{Git => }/IntegrationTestEnvironment.cs (100%) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 63c4d67bc..9d1e0ffd1 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -39,46 +39,103 @@ protected void Initialize() Logging.TracingEnabled = UserSettings.Get(Constants.TraceLoggingKey, false); ProcessManager = new ProcessManager(Environment, Platform.GitEnvironment, CancellationToken); Platform.Initialize(ProcessManager, TaskManager); - GitClient = new GitClient(Environment, ProcessManager, TaskManager); + ITaskManager taskManager = TaskManager; + GitClient = new GitClient(Environment, ProcessManager, taskManager.Token); SetupMetrics(); } public void Run(bool firstRun) { - new ActionTask(SetupGit()) + Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory); + + SetupGit() .Then(RestartRepository) .ThenInUI(InitializeUI) .Start(); } - private async Task SetupGit() + private ITask SetupGit() { - Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory); + return BuildDetermineGitPathTask() + .Then((b, path) => { + Logger.Trace("Setting GitExecutablePath: {0}", path); + Environment.GitExecutablePath = path; + }) + .Then(() => { + if (Environment.GitExecutablePath == null) + { + if (Environment.IsWindows) + { + GitClient.GetConfig("credential.helper", GitConfigSource.Global).Then( + (b, credentialHelper) => { + if (!string.IsNullOrEmpty(credentialHelper)) + { + Logger.Trace("Windows CredentialHelper: {0}", credentialHelper); + } + else + { + Logger.Warning( + "No Windows CredentialHeloper found: Setting to wincred"); + + GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global).Start().Wait(); + } + }); + } + } + }) + .ThenInUI(() => { + Environment.User.Initialize(GitClient); + }); + } - if (Environment.GitExecutablePath == null) + private TaskBase BuildDetermineGitPathTask() + { + TaskBase determinePath = new FuncTask(CancellationToken, () => { + if (Environment.GitExecutablePath != null) + { + return Environment.GitExecutablePath; + } + + var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath(); + if (gitExecutablePath != null && gitExecutablePath.FileExists()) + { + Logger.Trace("Using git install path from settings"); + return gitExecutablePath; + } + + return null; + }); + + var environmentIsWindows = Environment.IsWindows; + if (environmentIsWindows) { - Environment.GitExecutablePath = await DetermineGitExecutablePath(); + var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); + var installDetails = new PortableGitInstallDetails(applicationDataPath, true); + var installTask = new PortableGitInstallTask(CancellationToken, Environment, installDetails); - Logger.Trace("Environment.GitExecutablePath \"{0}\" Exists:{1}", Environment.GitExecutablePath, Environment.GitExecutablePath.FileExists()); + determinePath = determinePath.Then(new ShortCircuitTask(CancellationToken, installTask)); + } - if (Environment.IsWindows) - { - var credentialHelper = await GitClient.GetConfig("credential.helper", GitConfigSource.Global).StartAwait(); + if (!environmentIsWindows) + { + determinePath = determinePath.Then(new ShortCircuitTask(CancellationToken, () => { + var p = new NPath("/usr/local/bin/git"); - if (!string.IsNullOrEmpty(credentialHelper)) + if (p.FileExists()) { - Logger.Trace("Windows CredentialHelper: {0}", credentialHelper); + return p; } - else - { - Logger.Warning("No Windows CredentialHeloper found: Setting to wincred"); - await GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global).StartAwait(); - } - } + return null; + })); + + var findExecTask = new FindExecTask("git", CancellationToken); + findExecTask.Configure(ProcessManager); + + determinePath = determinePath.Then(new ShortCircuitTask(CancellationToken, findExecTask)); } - Environment.User.Initialize(GitClient); + return determinePath; } public ITask InitializeRepository() @@ -136,27 +193,6 @@ public void RestartRepository() } } - private async Task DetermineGitExecutablePath(ProgressReport progress = null) - { - var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath(); - if (gitExecutablePath != null && gitExecutablePath.FileExists()) - { - Logger.Trace("Using git install path from settings"); - return gitExecutablePath; - } - - var gitInstaller = new GitInstaller(Environment, CancellationToken); - var setupDone = await gitInstaller.SetupIfNeeded(progress?.Percentage, progress?.Remaining); - if (setupDone) - { - Logger.Trace("Setup performed using new path"); - return gitInstaller.GitExecutablePath; - } - - Logger.Trace("Finding git install path"); - return await GitClient.FindGitInstallation().SafeAwait(); - } - protected void SetupMetrics(string unityVersion, bool firstRun) { Logger.Trace("Setup metrics"); diff --git a/src/GitHub.Api/Git/GitClient.cs b/src/GitHub.Api/Git/GitClient.cs index a013eb9ee..3697f2173 100644 --- a/src/GitHub.Api/Git/GitClient.cs +++ b/src/GitHub.Api/Git/GitClient.cs @@ -8,7 +8,6 @@ namespace GitHub.Unity { public interface IGitClient { - Task FindGitInstallation(); ITask ValidateGitInstall(NPath path); ITask Init(IOutputProcessor processor = null); @@ -96,84 +95,13 @@ class GitClient : IGitClient private const string UserEmailConfigKey = "user.email"; private readonly IEnvironment environment; private readonly IProcessManager processManager; - private readonly ITaskManager taskManager; private readonly CancellationToken cancellationToken; - public GitClient(IEnvironment environment, IProcessManager processManager, ITaskManager taskManager) + public GitClient(IEnvironment environment, IProcessManager processManager, CancellationToken cancellationToken) { this.environment = environment; this.processManager = processManager; - this.taskManager = taskManager; - this.cancellationToken = taskManager.Token; - } - - public async Task FindGitInstallation() - { - if (!String.IsNullOrEmpty(environment.GitExecutablePath)) - return environment.GitExecutablePath; - - NPath path = null; - - if (environment.IsWindows) - path = await LookForPortableGit(); - - if (path == null) - path = await LookForSystemGit(); - - if (path == null) - { - Logger.Trace("Git Installation not discovered"); - } - else - { - Logger.Trace("Git Installation discovered: '{0}'", path); - } - - return path; - } - - private Task LookForPortableGit() - { - Logger.Trace("LookForPortableGit"); - - var gitHubLocalAppDataPath = environment.UserCachePath; - if (!gitHubLocalAppDataPath.DirectoryExists()) - return null; - - var searchPath = "PortableGit_"; - - var portableGitPath = gitHubLocalAppDataPath.Directories() - .Where(s => s.FileName.StartsWith(searchPath, StringComparison.OrdinalIgnoreCase)) - .FirstOrDefault(); - - if (portableGitPath != null) - { - portableGitPath = portableGitPath.Combine("cmd", $"git{environment.ExecutableExtension}"); - } - - return TaskEx.FromResult(portableGitPath); - } - - private async Task LookForSystemGit() - { - Logger.Trace("LookForSystemGit"); - - NPath path = null; - if (!environment.IsWindows) - { - var p = new NPath("/usr/local/bin/git"); - - if (p.FileExists()) - path = p; - } - - if (path == null) - { - path = await new FindExecTask("git", taskManager.Token) - .Configure(processManager).StartAwait(); - } - - return path; + this.cancellationToken = cancellationToken; } public ITask ValidateGitInstall(NPath path) diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index abe84e6eb..6b96d5c11 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -117,6 +117,8 @@ + + @@ -156,9 +158,7 @@ - - diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs deleted file mode 100644 index 1e7f397f9..000000000 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ /dev/null @@ -1,288 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace GitHub.Unity -{ - class GitInstaller : IGitInstaller - { - public const string WindowsGitLfsExecutableMD5 = "177bb14d0c08f665a24f0d5516c3b080"; - public const string MacGitLfsExecutableMD5 = "f81a1a065a26a4123193e8fd96c561ad"; - - private const string PortableGitExpectedVersion = "f02737a78695063deace08e96d5042710d3e32db"; - private const string PackageName = "PortableGit"; - private const string TempPathPrefix = "github-unity-portable"; - private const string GitZipFile = "git.zip"; - private const string GitLfsZipFile = "git-lfs.zip"; - - private readonly CancellationToken cancellationToken; - private readonly IEnvironment environment; - private readonly ILogging logger; - private readonly IZipHelper zipHelper; - - public GitInstaller(IEnvironment environment, CancellationToken cancellationToken) - : this(environment, ZipHelper.Instance, cancellationToken) - { - } - - public GitInstaller(IEnvironment environment, IZipHelper zipHelper, CancellationToken cancellationToken) - { - Guard.ArgumentNotNull(environment, nameof(environment)); - - logger = Logging.GetLogger(GetType()); - this.cancellationToken = cancellationToken; - - this.environment = environment; - this.zipHelper = zipHelper; - - GitInstallationPath = environment.GetSpecialFolder(Environment.SpecialFolder.LocalApplicationData) - .ToNPath().Combine(ApplicationInfo.ApplicationName, PackageNameWithVersion); - var gitExecutable = "git"; - var gitLfsExecutable = "git-lfs"; - if (DefaultEnvironment.OnWindows) - { - gitExecutable += ".exe"; - gitLfsExecutable += ".exe"; - } - GitLfsExecutable = gitLfsExecutable; - GitExecutable = gitExecutable; - - GitExecutablePath = GitInstallationPath; - if (DefaultEnvironment.OnWindows) - GitExecutablePath = GitExecutablePath.Combine("cmd"); - else - GitExecutablePath = GitExecutablePath.Combine("bin"); - GitExecutablePath = GitExecutablePath.Combine(GitExecutable); - - GitLfsExecutablePath = GitInstallationPath; - - if (DefaultEnvironment.OnWindows) - { - GitLfsExecutablePath = GitLfsExecutablePath.Combine("mingw32"); - } - - GitLfsExecutablePath = GitLfsExecutablePath.Combine("libexec", "git-core", GitLfsExecutable); - } - - public bool IsExtracted() - { - return IsPortableGitExtracted() && IsGitLfsExtracted(); - } - - private bool IsPortableGitExtracted() - { - if (!GitExecutablePath.FileExists()) - { - logger.Trace("{0} not installed yet", GitExecutablePath); - return false; - } - - logger.Trace("Git Present"); - - return true; - } - - public bool IsGitLfsExtracted() - { - if (!GitLfsExecutablePath.FileExists()) - { - logger.Trace("{0} not installed yet", GitLfsExecutablePath); - return false; - } - - var calculateMd5 = environment.FileSystem.CalculateMD5(GitLfsExecutablePath); - logger.Trace("GitLFS MD5: {0}", calculateMd5); - var md5 = environment.IsWindows ? WindowsGitLfsExecutableMD5 : MacGitLfsExecutableMD5; - if (String.Compare(calculateMd5, md5, true) != 0) - { - logger.Trace("{0} has incorrect MD5", GitExecutablePath); - return false; - } - - logger.Trace("GitLFS Present"); - - return true; - } - - public async Task SetupIfNeeded(IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) - { - logger.Trace("SetupIfNeeded"); - - cancellationToken.ThrowIfCancellationRequested(); - - NPath tempPath = null; - try - { - tempPath = NPath.CreateTempDirectory(TempPathPrefix); - - cancellationToken.ThrowIfCancellationRequested(); - - var ret = await SetupGitIfNeeded(tempPath, zipFileProgress, estimatedDurationProgress); - - cancellationToken.ThrowIfCancellationRequested(); - - ret &= await SetupGitLfsIfNeeded(tempPath, zipFileProgress, estimatedDurationProgress); - - tempPath.Delete(); - return ret; - } - catch (Exception ex) - { - logger.Trace(ex); - return false; - } - finally - { - try - { - if (tempPath != null) - tempPath.DeleteIfExists(); - } - catch {} - } - } - - public Task SetupGitIfNeeded(NPath tempPath, IProgress zipFileProgress = null, - IProgress estimatedDurationProgress = null) - { - logger.Trace("SetupGitIfNeeded"); - - cancellationToken.ThrowIfCancellationRequested(); - - if (IsPortableGitExtracted()) - { - logger.Trace("Already extracted {0}, returning", GitInstallationPath); - return TaskEx.FromResult(true); - } - - cancellationToken.ThrowIfCancellationRequested(); - - var archiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, GitZipFile, tempPath, environment); - if (!archiveFilePath.FileExists()) - { - logger.Warning("Archive \"{0}\" missing", archiveFilePath.ToString()); - - archiveFilePath = environment.ExtensionInstallPath.Combine(archiveFilePath); - if (!archiveFilePath.FileExists()) - { - logger.Warning("Archive \"{0}\" missing, returning", archiveFilePath.ToString()); - return TaskEx.FromResult(false); - } - } - - cancellationToken.ThrowIfCancellationRequested(); - - var unzipPath = tempPath.Combine("git"); - - try - { - logger.Trace("Extracting \"{0}\" to \"{1}\"", archiveFilePath, unzipPath); - - zipHelper.Extract(archiveFilePath, unzipPath, cancellationToken, zipFileProgress, - estimatedDurationProgress); - } - catch (Exception ex) - { - logger.Error(ex, "Error ExtractingArchive Source:\"{0}\" OutDir:\"{1}\"", archiveFilePath, tempPath); - return TaskEx.FromResult(false); - } - - cancellationToken.ThrowIfCancellationRequested(); - - try - { - GitInstallationPath.DeleteIfExists(); - GitInstallationPath.EnsureParentDirectoryExists(); - - logger.Trace("Moving \"{0}\" to \"{1}\"", unzipPath, GitInstallationPath); - - unzipPath.Move(GitInstallationPath); - } - catch (Exception ex) - { - logger.Error(ex, "Error Moving \"{0}\" to \"{1}\"", tempPath, GitInstallationPath); - return TaskEx.FromResult(false); - } - unzipPath.DeleteIfExists(); - return TaskEx.FromResult(true); - } - - public Task SetupGitLfsIfNeeded(NPath tempPath, IProgress zipFileProgress = null, - IProgress estimatedDurationProgress = null) - { - logger.Trace("SetupGitLfsIfNeeded"); - - cancellationToken.ThrowIfCancellationRequested(); - - if (IsGitLfsExtracted()) - { - logger.Trace("Already extracted {0}, returning", GitLfsExecutablePath); - return TaskEx.FromResult(false); - } - - cancellationToken.ThrowIfCancellationRequested(); - - var archiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, GitLfsZipFile, tempPath, environment); - if (!archiveFilePath.FileExists()) - { - logger.Warning("Archive \"{0}\" missing", archiveFilePath.ToString()); - - archiveFilePath = environment.ExtensionInstallPath.Combine(archiveFilePath); - if (!archiveFilePath.FileExists()) - { - logger.Warning("Archive \"{0}\" missing, returning", archiveFilePath.ToString()); - return TaskEx.FromResult(false); - } - } - - cancellationToken.ThrowIfCancellationRequested(); - - var unzipPath = tempPath.Combine("git-lfs"); - - try - { - logger.Trace("Extracting \"{0}\" to \"{1}\"", archiveFilePath, unzipPath); - - zipHelper.Extract(archiveFilePath, unzipPath, cancellationToken, zipFileProgress, - estimatedDurationProgress); - } - catch (Exception ex) - { - logger.Error(ex, "Error Extracting Archive:\"{0}\" OutDir:\"{1}\"", archiveFilePath, tempPath); - return TaskEx.FromResult(false); - } - - cancellationToken.ThrowIfCancellationRequested(); - - try - { - var unzippedGitLfsExecutablePath = unzipPath.Combine(GitLfsExecutable); - logger.Trace("Copying \"{0}\" to \"{1}\"", unzippedGitLfsExecutablePath, GitLfsExecutablePath); - - unzippedGitLfsExecutablePath.Copy(GitLfsExecutablePath); - } - catch (Exception ex) - { - logger.Error(ex, "Error Copying git-lfs Source:\"{0}\" Destination:\"{1}\"", unzipPath, GitLfsExecutablePath); - return TaskEx.FromResult(false); - } - unzipPath.DeleteIfExists(); - return TaskEx.FromResult(true); - } - - private NPath GetTemporaryPath() - { - return NPath.CreateTempDirectory(TempPathPrefix); - } - - public NPath GitInstallationPath { get; private set; } - - public NPath GitLfsExecutablePath { get; private set; } - - public NPath GitExecutablePath { get; private set; } - public string PackageNameWithVersion => PackageName + "_" + PortableGitExpectedVersion; - - private string GitLfsExecutable { get; set; } - private string GitExecutable { get; set; } - } -} diff --git a/src/GitHub.Api/Installer/IGitInstaller.cs b/src/GitHub.Api/Installer/IGitInstaller.cs deleted file mode 100644 index f137e5f2b..000000000 --- a/src/GitHub.Api/Installer/IGitInstaller.cs +++ /dev/null @@ -1,13 +0,0 @@ -using GitHub.Unity; -using System; -using System.Threading.Tasks; - -namespace GitHub.Unity -{ - interface IGitInstaller - { - bool IsExtracted(); - NPath GitInstallationPath { get; } - string PackageNameWithVersion { get; } - } -} diff --git a/src/GitHub.Api/Installer/PortableGitInstallTask.cs b/src/GitHub.Api/Installer/PortableGitInstallTask.cs new file mode 100644 index 000000000..4f68d7dee --- /dev/null +++ b/src/GitHub.Api/Installer/PortableGitInstallTask.cs @@ -0,0 +1,209 @@ +using System; +using System.Threading; + +namespace GitHub.Unity +{ + class PortableGitInstallDetails + { + public NPath GitInstallPath { get; } + public string GitExec { get; } + public NPath GitExecPath { get; } + public string GitLfsExec { get; } + public NPath GitLfsExecPath { get; } + + public const string ExtractedMD5 = "65fd0575d3b47d8207b9e19d02faca4f"; + + private const string ExpectedVersion = "f02737a78695063deace08e96d5042710d3e32db"; + private const string PackageName = "PortableGit"; + private const string PackageNameWithVersion = PackageName + "_" + ExpectedVersion; + + public PortableGitInstallDetails(NPath targetInstallPath, bool onWindows) + { + var gitInstallPath = targetInstallPath.Combine(ApplicationInfo.ApplicationName, PackageNameWithVersion); + GitInstallPath = gitInstallPath; + + if (onWindows) + { + GitExec += "git.exe"; + GitLfsExec += "git-lfs.exe"; + + GitExecPath = gitInstallPath.Combine("cmd", GitExec); + GitLfsExecPath = gitInstallPath.Combine("mingw32", "libexec", "git-core", GitLfsExec); + } + else + { + GitExec = "git"; + GitLfsExec = "git-lfs"; + + GitExecPath = gitInstallPath.Combine("bin", GitExec); + GitLfsExecPath = gitInstallPath.Combine("libexec", "git-core", GitLfsExec); + } + } + } + + class PortableGitInstallTask : TaskBase + { + private readonly PortableGitInstallDetails installDetails; + private readonly IEnvironment environment; + + public PortableGitInstallTask(CancellationToken token, IEnvironment environment, PortableGitInstallDetails installDetails) : base(token) + { + this.environment = environment; + this.installDetails = installDetails; + } + + protected override NPath RunWithReturn(bool success) + { + base.RunWithReturn(success); + + Logger.Trace("Starting PortableGitInstallTask"); + + if (IsPortableGitExtracted()) + { + Logger.Trace("Completed PortableGitInstallTask"); + return installDetails.GitExecPath; + } + + var installGit = InstallGit(); + if (installGit) + { + var installGitLfs = InstallGitLfs(); + if (installGitLfs) + { + Logger.Trace("Completed PortableGitInstallTask"); + return installDetails.GitExecPath; + } + } + + Logger.Warning("Unsuccessful PortableGitInstallTask"); + + return null; + } + + private bool IsPortableGitExtracted() + { + if (!installDetails.GitInstallPath.DirectoryExists()) + { + Logger.Trace("{0} does not exist", installDetails.GitInstallPath); + return false; + } + + var installMD5 = environment.FileSystem.CalculateFolderMD5(installDetails.GitInstallPath); + if (!installMD5.Equals(PortableGitInstallDetails.ExtractedMD5, StringComparison.InvariantCultureIgnoreCase)) + { + Logger.Trace("MD5 {0} does not match expected {1}", installMD5, PortableGitInstallDetails.ExtractedMD5); + return false; + } + + Logger.Trace("Git Present"); + return true; + } + + private bool InstallGit() + { + Logger.Trace("InstallGit"); + + var tempPath = NPath.GetTempFilename(); + var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", tempPath, environment); + + if (!environment.FileSystem.FileExists(gitArchivePath)) + { + Logger.Warning("Archive \"{0}\" missing", gitArchivePath); + + return false; + } + + Token.ThrowIfCancellationRequested(); + + var tempDirectory = NPath.CreateTempDirectory("git_install_task"); + + try + { + Logger.Trace("Extracting gitArchivePath:\"{0}\" tempDirectory:\"{1}\"", + gitArchivePath, tempDirectory); + + ZipHelper.ExtractZipFile(gitArchivePath, tempDirectory, Token); + } + catch (Exception ex) + { + Logger.Warning(ex, "Error Extracting gitArchivePath:\"{0}\" tempDirectory:\"{1}\"", + gitArchivePath, tempDirectory); + + return false; + } + + Token.ThrowIfCancellationRequested(); + + try + { + installDetails.GitInstallPath.DeleteIfExists(); + installDetails.GitInstallPath.EnsureParentDirectoryExists(); + + Logger.Trace("Moving tempDirectory:\"{0}\" to gitInstallPath:\"{1}\"", + tempDirectory, installDetails.GitInstallPath); + + tempDirectory.Move(installDetails.GitInstallPath); + } + catch (Exception ex) + { + Logger.Warning(ex, "Error Moving tempDirectory:\"{0}\" to gitInstallPath:\"{1}\"", + tempDirectory, installDetails.GitInstallPath); + + return false; + } + + Logger.Trace("Deleting tempDirectory:\"{0}\"", tempDirectory); + tempDirectory.DeleteIfExists(); + + return true; + } + + private bool InstallGitLfs() + { + Logger.Trace("InstallGitLfs"); + + var tempPath = NPath.GetTempFilename(); + var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", tempPath, environment); + + if (!environment.FileSystem.FileExists(gitLfsArchivePath)) + { + Logger.Warning($"Archive \"{gitLfsArchivePath}\" missing"); + return false; + } + + Token.ThrowIfCancellationRequested(); + + var tempDirectory = NPath.CreateTempDirectory("git_install_task"); + + try + { + Logger.Trace("Extracting gitLfsArchivePath:\"{0}\" tempDirectory:\"{1}\"", gitLfsArchivePath, tempDirectory); + ZipHelper.ExtractZipFile(gitLfsArchivePath, tempDirectory, Token); + } + catch (Exception ex) + { + Logger.Warning($"Error Extracting gitLfsArchivePath:\"{gitLfsArchivePath}\" tempDirectory:\"{tempDirectory}\"", ex); + return false; + } + + Token.ThrowIfCancellationRequested(); + + var tempDirectoryGitLfsExec = tempDirectory.Combine(installDetails.GitLfsExec); + + try + { + Logger.Trace("Moving tempDirectoryGitLfsExec:\"{0}\" to gitLfsExecFullPath:\"{1}\"", tempDirectoryGitLfsExec, installDetails.GitLfsExecPath); + tempDirectoryGitLfsExec.Move(installDetails.GitLfsExecPath); + } + catch (Exception ex) + { + Logger.Warning($"Error Moving tempDirectoryGitLfsExec:\"{tempDirectoryGitLfsExec}\" to gitLfsExecFullPath:\"{installDetails.GitLfsExecPath}\"", ex); + return false; + } + + Logger.Trace("Deleting tempDirectory:\"{0}\"", tempDirectory); + tempDirectory.DeleteIfExists(); + return true; + } + } +} \ No newline at end of file diff --git a/src/GitHub.Api/Installer/ShortCircuitTask.cs b/src/GitHub.Api/Installer/ShortCircuitTask.cs new file mode 100644 index 000000000..c925fb2ec --- /dev/null +++ b/src/GitHub.Api/Installer/ShortCircuitTask.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading; + +namespace GitHub.Unity +{ + class ShortCircuitTask : TaskBase + { + private readonly Func action; + + public ShortCircuitTask(CancellationToken token, TaskBase funcTask) : base(token) + { + action = () => funcTask.Start().Result; + } + + public ShortCircuitTask(CancellationToken token, Func action) : base(token) + { + this.action = action; + } + + protected override TResult RunWithData(bool success, TResult previousResult) + { + base.RunWithData(success, previousResult); + + if (success && previousResult != null) + { + return previousResult; + } + + return action(); + } + } +} \ No newline at end of file diff --git a/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs b/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs index fc6399b3c..376c6bde1 100644 --- a/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs +++ b/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs @@ -2,18 +2,17 @@ using System.IO; using System.Linq; using System.Threading; -using System.Threading.Tasks; using GitHub.Unity; namespace IntegrationTests { class BaseGitEnvironmentTest : BasePlatformIntegrationTest { - protected async Task Initialize(NPath repoPath, NPath environmentPath = null, + protected IEnvironment Initialize(NPath repoPath, NPath environmentPath = null, bool enableEnvironmentTrace = false, bool initializeRepository = true, Action onRepositoryManagerCreated = null) { - await InitializePlatform(repoPath, environmentPath, enableEnvironmentTrace); + InitializePlatform(repoPath, environmentPath, enableEnvironmentTrace); var repositoryManager = GitHub.Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, repoPath); diff --git a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs index 180ce7063..c8c6e6d27 100644 --- a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs +++ b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Threading; using System.Threading.Tasks; using GitHub.Unity; using NSubstitute; @@ -9,11 +10,11 @@ class BasePlatformIntegrationTest : BaseTaskManagerTest { protected IPlatform Platform { get; private set; } protected IProcessManager ProcessManager { get; private set; } - protected IProcessEnvironment GitEnvironment { get; private set; } + protected IProcessEnvironment GitEnvironment => Platform.GitEnvironment; protected IGitClient GitClient { get; set; } public ICacheContainer CacheContainer { get; set; } - protected async Task InitializePlatform(NPath repoPath, NPath environmentPath, bool enableEnvironmentTrace) + protected void InitializePlatform(NPath repoPath, NPath environmentPath, bool enableEnvironmentTrace, bool setupGit = true) { InitializeTaskManager(); @@ -21,18 +22,22 @@ protected async Task InitializePlatform(NPath repoPath, NPath environmentPath, b Environment = new IntegrationTestEnvironment(CacheContainer, repoPath, SolutionDirectory, environmentPath, enableEnvironmentTrace); - var gitSetup = new GitInstaller(Environment, TaskManager.Token); - await gitSetup.SetupIfNeeded(); - Environment.GitExecutablePath = gitSetup.GitExecutablePath; - Platform = new Platform(Environment); - - GitEnvironment = Platform.GitEnvironment; ProcessManager = new ProcessManager(Environment, GitEnvironment, TaskManager.Token); Platform.Initialize(ProcessManager, TaskManager); - GitClient = new GitClient(Environment, ProcessManager, TaskManager); + if (setupGit) + { + var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); + var installDetails = new PortableGitInstallDetails(applicationDataPath, true); + var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, installDetails); + + var installPath = gitInstallTask.Start().Result; + Environment.GitExecutablePath = installPath; + + GitClient = new GitClient(Environment, ProcessManager, TaskManager.Token); + } } } } diff --git a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs index 44191d1b3..0d5a1af24 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -24,7 +24,7 @@ public override void OnSetup() } [Test] - public async Task ShouldPerformBasicInitialize() + public void ShouldPerformBasicInitialize() { Logger.Trace("Starting ShouldPerformBasicInitialize"); @@ -32,7 +32,7 @@ public async Task ShouldPerformBasicInitialize() { var repositoryManagerListener = Substitute.For(); - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, onRepositoryManagerCreated: manager => { repositoryManagerListener.AttachListener(manager, repositoryManagerEvents); }); @@ -69,7 +69,7 @@ public async Task ShouldDetectFileChanges() { var repositoryManagerListener = Substitute.For(); - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, onRepositoryManagerCreated: manager => { repositoryManagerListener.AttachListener(manager, repositoryManagerEvents); }); @@ -119,7 +119,7 @@ public async Task ShouldAddAndCommitFiles() { var repositoryManagerListener = Substitute.For(); - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, onRepositoryManagerCreated: manager => { repositoryManagerListener.AttachListener(manager, repositoryManagerEvents); }); @@ -197,7 +197,7 @@ public async Task ShouldAddAndCommitAllFiles() { var repositoryManagerListener = Substitute.For(); - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, onRepositoryManagerCreated: manager => { repositoryManagerListener.AttachListener(manager, repositoryManagerEvents); }); @@ -275,7 +275,7 @@ public async Task ShouldDetectBranchChange() { var repositoryManagerListener = Substitute.For(); - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, onRepositoryManagerCreated: manager => { repositoryManagerListener.AttachListener(manager, repositoryManagerEvents); }); @@ -325,7 +325,7 @@ public async Task ShouldDetectBranchDelete() { var repositoryManagerListener = Substitute.For(); - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, onRepositoryManagerCreated: manager => { repositoryManagerListener.AttachListener(manager, repositoryManagerEvents); }); @@ -377,7 +377,7 @@ public async Task ShouldDetectBranchCreate() { var repositoryManagerListener = Substitute.For(); - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, onRepositoryManagerCreated: manager => { repositoryManagerListener.AttachListener(manager, repositoryManagerEvents); }); @@ -446,7 +446,7 @@ public async Task ShouldDetectChangesToRemotes() { var repositoryManagerListener = Substitute.For(); - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, onRepositoryManagerCreated: manager => { repositoryManagerListener.AttachListener(manager, repositoryManagerEvents); }); @@ -522,7 +522,7 @@ public async Task ShouldDetectChangesToRemotesWhenSwitchingBranches() { var repositoryManagerListener = Substitute.For(); - await Initialize(TestRepoMasterTwoRemotes, initializeRepository: false, + Initialize(TestRepoMasterTwoRemotes, initializeRepository: false, onRepositoryManagerCreated: manager => { repositoryManagerListener.AttachListener(manager, repositoryManagerEvents); }); @@ -598,7 +598,7 @@ public async Task ShouldDetectGitPull() { var repositoryManagerListener = Substitute.For(); - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false, onRepositoryManagerCreated: manager => { repositoryManagerListener.AttachListener(manager, repositoryManagerEvents); }); @@ -647,7 +647,7 @@ public async Task ShouldDetectGitFetch() { var repositoryManagerListener = Substitute.For(); - await Initialize(TestRepoMasterCleanUnsynchronized, initializeRepository: false, + Initialize(TestRepoMasterCleanUnsynchronized, initializeRepository: false, onRepositoryManagerCreated: manager => { repositoryManagerListener.AttachListener(manager, repositoryManagerEvents); }); diff --git a/src/tests/IntegrationTests/Events/RepositoryWatcherTests.cs b/src/tests/IntegrationTests/Events/RepositoryWatcherTests.cs index 28a0e615b..63dbdc78d 100644 --- a/src/tests/IntegrationTests/Events/RepositoryWatcherTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryWatcherTests.cs @@ -19,7 +19,7 @@ public async Task ShouldDetectFileChangesAndCommit() try { - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false); + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false); using (var repositoryWatcher = CreateRepositoryWatcher(TestRepoMasterCleanSynchronized)) { @@ -117,7 +117,7 @@ public async Task ShouldDetectBranchChange() try { - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false); + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false); using (var repositoryWatcher = CreateRepositoryWatcher(TestRepoMasterCleanSynchronized)) { @@ -174,7 +174,7 @@ public async Task ShouldDetectBranchDelete() try { - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false); + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false); using (var repositoryWatcher = CreateRepositoryWatcher(TestRepoMasterCleanSynchronized)) { @@ -229,7 +229,7 @@ public async Task ShouldDetectBranchCreate() try { - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false); + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false); using (var repositoryWatcher = CreateRepositoryWatcher(TestRepoMasterCleanSynchronized)) { @@ -305,7 +305,7 @@ public async Task ShouldDetectChangesToRemotes() try { - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false); + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false); using (var repositoryWatcher = CreateRepositoryWatcher(TestRepoMasterCleanSynchronized)) { @@ -381,7 +381,7 @@ public async Task ShouldDetectGitPull() try { - await Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false); + Initialize(TestRepoMasterCleanSynchronized, initializeRepository: false); using (var repositoryWatcher = CreateRepositoryWatcher(TestRepoMasterCleanSynchronized)) { @@ -435,7 +435,7 @@ public async Task ShouldDetectGitFetch() try { - await Initialize(TestRepoMasterCleanUnsynchronized, initializeRepository: false); + Initialize(TestRepoMasterCleanUnsynchronized, initializeRepository: false); using (var repositoryWatcher = CreateRepositoryWatcher(TestRepoMasterCleanUnsynchronized)) { diff --git a/src/tests/IntegrationTests/GitClientTests.cs b/src/tests/IntegrationTests/Git/GitClientTests.cs similarity index 81% rename from src/tests/IntegrationTests/GitClientTests.cs rename to src/tests/IntegrationTests/Git/GitClientTests.cs index 7acb2250d..cfa19c055 100644 --- a/src/tests/IntegrationTests/GitClientTests.cs +++ b/src/tests/IntegrationTests/Git/GitClientTests.cs @@ -10,9 +10,9 @@ namespace IntegrationTests class GitClientTests : BaseGitEnvironmentTest { [Test] - public async Task ShouldGetGitVersion() + public void ShouldGetGitVersion() { - await Initialize(TestRepoMasterCleanSynchronized); + Initialize(TestRepoMasterCleanSynchronized); var version = GitClient.Version(); version.Start().Wait(); @@ -29,9 +29,9 @@ public async Task ShouldGetGitVersion() } [Test] - public async Task ShouldGetGitLfsVersion() + public void ShouldGetGitLfsVersion() { - await Initialize(TestRepoMasterCleanSynchronized); + Initialize(TestRepoMasterCleanSynchronized); var version = GitClient.LfsVersion(); version.Start().Wait(); diff --git a/src/tests/IntegrationTests/Git/GitSetupTests.cs b/src/tests/IntegrationTests/Git/GitSetupTests.cs deleted file mode 100644 index 1a18cdc8b..000000000 --- a/src/tests/IntegrationTests/Git/GitSetupTests.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System.Collections.Generic; -using FluentAssertions; -using GitHub.Unity; -using NUnit.Framework; -using Rackspace.Threading; -using System.Threading.Tasks; -using ICSharpCode.SharpZipLib.Zip; - -namespace IntegrationTests -{ - class GitSetupTests : BaseGitEnvironmentTest - { - [Test, Category("DoNotRunOnAppVeyor")] - public async Task InstallGit() - { - var environmentPath = NPath.CreateTempDirectory("integration-test-environment"); - var environment = await Initialize(TestRepoMasterDirtyUnsynchronized, environmentPath); - - var gitSetup = new GitInstaller(environment, TaskManager.Token); - var expectedPath = gitSetup.GitInstallationPath; - - var setupDone = false; - var percent = -1f; - gitSetup.GitExecutablePath.FileExists().Should().BeFalse(); - - setupDone = await gitSetup.SetupIfNeeded(new Progress(x => percent = x)); - - if (environment.IsWindows) - { - environment.GitExecutablePath = gitSetup.GitExecutablePath; - - setupDone.Should().BeTrue(); - percent.Should().Be(1); - - Logger.Trace("Expected GitExecutablePath: {0}", gitSetup.GitExecutablePath); - gitSetup.GitExecutablePath.FileExists().Should().BeTrue(); - - var gitLfsDestinationPath = gitSetup.GitInstallationPath; - gitLfsDestinationPath = gitLfsDestinationPath.Combine("mingw32"); - - gitLfsDestinationPath = gitLfsDestinationPath.Combine("libexec", "git-core", "git-lfs.exe"); - gitLfsDestinationPath.FileExists().Should().BeTrue(); - - var calculateMd5 = NPath.FileSystem.CalculateMD5(gitLfsDestinationPath); - Assert.IsTrue(string.Compare(calculateMd5, GitInstaller.WindowsGitLfsExecutableMD5, true) == 0); - - setupDone = await gitSetup.SetupIfNeeded(new Progress(x => percent = x)); - setupDone.Should().BeFalse(); - } - else - { - environment.GitExecutablePath = "/usr/local/bin/git".ToNPath(); - setupDone.Should().BeFalse(); - } - - var platform = new Platform(environment); - var gitEnvironment = platform.GitEnvironment; - var processManager = new ProcessManager(environment, gitEnvironment, TaskManager.Token); - - List gitBranches = null; - gitBranches = await processManager - .GetGitBranches(TestRepoMasterDirtyUnsynchronized, environment.GitExecutablePath) - .StartAsAsync(); - - gitBranches.Should().BeEquivalentTo( - new GitBranch("master", "origin/master: behind 1", true), - new GitBranch("feature/document", "origin/feature/document", false)); - } - - - [Test] - public void VerifyWindowsGitLfsBundle() - { - var environmentPath = NPath.CreateTempDirectory("integration-test-environment"); - - var gitLfsPath = environmentPath.Combine("git-lfs.exe"); - gitLfsPath.Exists().Should().BeFalse(); - - var inputZipFile = SolutionDirectory.Combine("PlatformResources", "windows", "git-lfs.zip"); - - var fastZip = new FastZip(); - fastZip.ExtractZip(inputZipFile, environmentPath, null); - - gitLfsPath.Exists().Should().BeTrue(); - - var calculateMd5 = NPath.FileSystem.CalculateMD5(gitLfsPath); - calculateMd5.ToLower().Should().Be(GitInstaller.WindowsGitLfsExecutableMD5.ToLower()); - } - - - [Test] - public void VerifyMacGitLfsBundle() - { - var environmentPath = NPath.CreateTempDirectory("integration-test-environment"); - - var gitLfsPath = environmentPath.Combine("git-lfs"); - gitLfsPath.Exists().Should().BeFalse(); - - var inputZipFile = SolutionDirectory.Combine("PlatformResources", "mac", "git-lfs.zip"); - - var fastZip = new FastZip(); - fastZip.ExtractZip(inputZipFile, environmentPath, null); - - gitLfsPath.Exists().Should().BeTrue(); - - var calculateMd5 = NPath.FileSystem.CalculateMD5(gitLfsPath); - calculateMd5.ToLower().Should().Be(GitInstaller.MacGitLfsExecutableMD5.ToLower()); - } - } -} \ No newline at end of file diff --git a/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs b/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs new file mode 100644 index 000000000..a8b2f1fd5 --- /dev/null +++ b/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs @@ -0,0 +1,36 @@ +using System.Threading; +using FluentAssertions; +using GitHub.Unity; +using NSubstitute; +using NUnit.Framework; + +namespace IntegrationTests +{ + [TestFixture] + class PortableGitInstallTaskTests : BaseTaskManagerTest + { + [Test] + public void GitInstallTest() + { + InitializeTaskManager(); + + var cacheContainer = Substitute.For(); + Environment = new IntegrationTestEnvironment(cacheContainer, TestBasePath, SolutionDirectory, enableTrace: true); + + var gitInstallationPath = TestBasePath.Combine("GitInstall").CreateDirectory(); + + var gitInstallDetails = new PortableGitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows); + var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails); + + gitInstallTask.Start().Wait(); + + var calculateFolderMd5 = Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath); + calculateFolderMd5.Should().Be(PortableGitInstallDetails.ExtractedMD5); + + new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails) + .Then(new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails)) + .Start() + .Wait(); + } + } +} \ No newline at end of file diff --git a/src/tests/IntegrationTests/Installer/ShortCircuitTaskTests.cs b/src/tests/IntegrationTests/Installer/ShortCircuitTaskTests.cs new file mode 100644 index 000000000..1d5a69842 --- /dev/null +++ b/src/tests/IntegrationTests/Installer/ShortCircuitTaskTests.cs @@ -0,0 +1,71 @@ +using System.Threading; +using FluentAssertions; +using GitHub.Unity; +using NUnit.Framework; + +namespace IntegrationTests +{ + [TestFixture] + class ShortCircuitTaskTests : BaseTaskManagerTest + { + [Test] + public void ShouldSkipSecondTask() + { + InitializeTaskManager(); + Logger.Trace("ShouldSkipSecondTask"); + + var calledFirst = false; + var first = new FuncTask(CancellationToken.None, () => { + Logger.Trace("Returning First"); + calledFirst = true; + return "First"; + }); + + var calledSecond = false; + var second = new FuncTask(CancellationToken.None, () => { + Logger.Trace("Returning Second"); + calledSecond = true; + return "Second"; + }); + + var shortCircuitTask = new ShortCircuitTask(CancellationToken.None, second); + + var result = first + .Then(shortCircuitTask).Start().Result; + + result.Should().Be("First"); + calledFirst.Should().BeTrue(); + calledSecond.Should().BeFalse(); + } + + [Test] + public void ShouldRunSecondTask() + { + InitializeTaskManager(); + Logger.Trace("ShouldRunSecondTask"); + + var calledFirst = false; + var first = new FuncTask(CancellationToken.None, () => { + Logger.Trace("Returning First"); + calledFirst = true; + return null; + }); + + var calledSecond = false; + var second = new FuncTask(CancellationToken.None, () => { + Logger.Trace("Returning Second"); + calledSecond = true; + return "Second"; + }); + + var shortCircuitTask = new ShortCircuitTask(CancellationToken.None, second); + + var result = first + .Then(shortCircuitTask).Start().Result; + + result.Should().Be("Second"); + calledFirst.Should().BeTrue(); + calledSecond.Should().BeTrue(); + } + } +} \ No newline at end of file diff --git a/src/tests/IntegrationTests/Git/IntegrationTestEnvironment.cs b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs similarity index 100% rename from src/tests/IntegrationTests/Git/IntegrationTestEnvironment.cs rename to src/tests/IntegrationTests/IntegrationTestEnvironment.cs diff --git a/src/tests/IntegrationTests/IntegrationTests.csproj b/src/tests/IntegrationTests/IntegrationTests.csproj index 4c8d3da01..bf23c591f 100644 --- a/src/tests/IntegrationTests/IntegrationTests.csproj +++ b/src/tests/IntegrationTests/IntegrationTests.csproj @@ -79,14 +79,16 @@ - - - + + + + + diff --git a/src/tests/IntegrationTests/Process/ProcessManagerIntegrationTests.cs b/src/tests/IntegrationTests/Process/ProcessManagerIntegrationTests.cs index 0d1f80913..4653e7775 100644 --- a/src/tests/IntegrationTests/Process/ProcessManagerIntegrationTests.cs +++ b/src/tests/IntegrationTests/Process/ProcessManagerIntegrationTests.cs @@ -15,7 +15,7 @@ class ProcessManagerIntegrationTests : BaseGitEnvironmentTest [Test] public async Task BranchListTest() { - await Initialize(TestRepoMasterCleanUnsynchronized); + Initialize(TestRepoMasterCleanUnsynchronized); IEnumerable gitBranches = null; gitBranches = await ProcessManager @@ -30,7 +30,7 @@ public async Task BranchListTest() [Test] public async Task LogEntriesTest() { - await Initialize(TestRepoMasterCleanUnsynchronized); + Initialize(TestRepoMasterCleanUnsynchronized); List logEntries = null; logEntries = await ProcessManager @@ -71,7 +71,7 @@ public async Task LogEntriesTest() [Test] public async Task RussianLogEntriesTest() { - await Initialize(TestRepoMasterCleanUnsynchronizedRussianLanguage); + Initialize(TestRepoMasterCleanUnsynchronizedRussianLanguage); List logEntries = null; logEntries = await ProcessManager @@ -99,7 +99,7 @@ public async Task RussianLogEntriesTest() [Test] public async Task RemoteListTest() { - await Initialize(TestRepoMasterCleanSynchronized); + Initialize(TestRepoMasterCleanSynchronized); List gitRemotes = null; gitRemotes = await ProcessManager @@ -112,7 +112,7 @@ public async Task RemoteListTest() [Test] public async Task StatusTest() { - await Initialize(TestRepoMasterDirtyUnsynchronized); + Initialize(TestRepoMasterDirtyUnsynchronized); GitStatus? gitStatus = null; gitStatus = await ProcessManager @@ -147,7 +147,7 @@ public async Task StatusTest() [Test] public async Task CredentialHelperGetTest() { - await Initialize(TestRepoMasterCleanSynchronized); + Initialize(TestRepoMasterCleanSynchronized); await ProcessManager .GetGitCreds(TestRepoMasterCleanSynchronized, Environment, GitEnvironment) From ed03a78960cc151094ca551356260e8e2c0022e0 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 28 Dec 2017 17:11:14 -0500 Subject: [PATCH 0019/1008] Preventing the usage of InitProjectView and SettingsView if GitClient is not ready --- .../Assets/Editor/GitHub.Unity/UI/GitPathView.cs | 9 ++++++++- .../Assets/Editor/GitHub.Unity/UI/InitProjectView.cs | 11 +++++++++-- .../Assets/Editor/GitHub.Unity/UI/UserSettingsView.cs | 9 +++------ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs index 37db8aa24..76711c168 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/GitPathView.cs @@ -30,6 +30,13 @@ class GitPathView : Subview [NonSerialized] private bool isBusy; [NonSerialized] private bool gitExecHasChanged; + [NonSerialized] private bool gitExecutableIsSet; + + public override void InitializeView(IView parent) + { + base.InitializeView(parent); + gitExecutableIsSet = Environment.GitExecutablePath != null; + } public override void OnEnable() { @@ -48,7 +55,7 @@ public override void OnGUI() // Install path GUILayout.Label(GitInstallTitle, EditorStyles.boldLabel); - EditorGUI.BeginDisabledGroup(IsBusy || Parent.IsBusy); + EditorGUI.BeginDisabledGroup(!gitExecutableIsSet || IsBusy || Parent.IsBusy); { // Install path field GUILayout.BeginHorizontal(); diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs index 0eafee598..e7c0ca085 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs @@ -17,6 +17,13 @@ class InitProjectView : Subview [NonSerialized] private bool isBusy; [NonSerialized] private bool userHasChanges; + [NonSerialized] private bool gitExecutableIsSet; + + public override void InitializeView(IView parent) + { + base.InitializeView(parent); + gitExecutableIsSet = Environment.GitExecutablePath != null; + } public override void OnEnable() { @@ -54,7 +61,7 @@ public override void OnGUI() { GUILayout.FlexibleSpace(); - EditorGUI.BeginDisabledGroup(IsBusy || !isUserDataPresent); + EditorGUI.BeginDisabledGroup(!gitExecutableIsSet || IsBusy || !isUserDataPresent); { if (GUILayout.Button(Localization.InitializeRepositoryButtonText, "Button")) { @@ -70,7 +77,7 @@ public override void OnGUI() } GUILayout.EndHorizontal(); - if (hasCompletedInitialCheck && !isUserDataPresent) + if (gitExecutableIsSet && hasCompletedInitialCheck && !isUserDataPresent) { EditorGUILayout.Space(); EditorGUILayout.HelpBox(NoUserOrEmailError, MessageType.Error); diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/UserSettingsView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/UserSettingsView.cs index 825d35399..4d78a6c33 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/UserSettingsView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/UserSettingsView.cs @@ -7,9 +7,6 @@ namespace GitHub.Unity [Serializable] class UserSettingsView : Subview { - private static readonly Vector2 viewSize = new Vector2(325, 125); - private const string WindowTitle = "User Settings"; - private const string GitConfigTitle = "Git Configuration"; private const string GitConfigNameLabel = "Name"; private const string GitConfigEmailLabel = "Email"; @@ -24,12 +21,12 @@ class UserSettingsView : Subview [NonSerialized] private bool isBusy; [NonSerialized] private bool userHasChanges; + [NonSerialized] private bool gitExecutableIsSet; public override void InitializeView(IView parent) { base.InitializeView(parent); - Title = WindowTitle; - Size = viewSize; + gitExecutableIsSet = Environment.GitExecutablePath != null; } public override void OnDataUpdate() @@ -42,7 +39,7 @@ public override void OnGUI() { GUILayout.Label(GitConfigTitle, EditorStyles.boldLabel); - EditorGUI.BeginDisabledGroup(IsBusy || Parent.IsBusy); + EditorGUI.BeginDisabledGroup(!gitExecutableIsSet || IsBusy || Parent.IsBusy); { EditorGUI.BeginChangeCheck(); { From bf322837e2ed211a0f3570c863e32f02070fd826 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 28 Dec 2017 17:22:54 -0500 Subject: [PATCH 0020/1008] TaskBase null fix When this class is dervied and used with no task set as it's dependency. It returns a false for success and should return a default value for T --- src/GitHub.Api/Tasks/TaskBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index cafd4fd20..d54f24d76 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -597,7 +597,7 @@ public TaskBase(CancellationToken token) { Task = new Task(() => { - var ret = RunWithData(DependsOn?.Successful ?? previousSuccess, DependsOn.Successful ? ((ITask)DependsOn).Result : default(T)); + var ret = RunWithData(DependsOn?.Successful ?? previousSuccess, (DependsOn?.Successful ?? false) ? ((ITask)DependsOn).Result : default(T)); tcs.SetResult(ret); AdjustNextTask(ret); return ret; From c0ee280152a39abdf71f22d78596f838f7b6133e Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 28 Dec 2017 17:47:24 -0500 Subject: [PATCH 0021/1008] Integrating the LoadingView to the main Window --- .../Editor/GitHub.Unity/UI/LoadingView.cs | 17 ++++------ .../Assets/Editor/GitHub.Unity/UI/Window.cs | 34 +++++++++++++++---- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/LoadingView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/LoadingView.cs index d5d4b3341..83a3a3f73 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/LoadingView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/LoadingView.cs @@ -1,30 +1,25 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Octokit; -using Rackspace.Threading; -using UnityEditor; +using UnityEditor; using UnityEngine; namespace GitHub.Unity { class LoadingView : Subview { - private static readonly Vector2 viewSize = new Vector2(300, 250); + private static readonly Vector2 MinViewSize = new Vector2(300, 250); private const string WindowTitle = "Loading..."; - private const string Header = ""; - public override void InitializeView(IView parent) { base.InitializeView(parent); Title = WindowTitle; - Size = viewSize; + Size = MinViewSize; } public override void OnGUI() - {} + { + + } public override bool IsBusy { diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs index 54afa6a1e..026cd05ab 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs @@ -26,6 +26,7 @@ class Window : BaseWindow [SerializeField] private SubTab changeTab = SubTab.History; [SerializeField] private SubTab activeTab = SubTab.History; [SerializeField] private InitProjectView initProjectView = new InitProjectView(); + [SerializeField] private LoadingView loadingView = new LoadingView(); [SerializeField] private BranchesView branchesView = new BranchesView(); [SerializeField] private ChangesView changesView = new ChangesView(); [SerializeField] private HistoryView historyView = new HistoryView(); @@ -39,6 +40,7 @@ class Window : BaseWindow [SerializeField] private CacheUpdateEvent lastCurrentBranchAndRemoteChangedEvent; [NonSerialized] private bool currentBranchAndRemoteHasUpdate; + [NonSerialized] private bool gitExecutableIsSet; [MenuItem(LaunchMenu)] public static void Window_GitHub() @@ -84,9 +86,18 @@ public override void Initialize(IApplicationManager applicationManager) { base.Initialize(applicationManager); - if (!HasRepository && activeTab != SubTab.InitProject && activeTab != SubTab.Settings) + gitExecutableIsSet = Environment.GitExecutablePath != null; + + if (!gitExecutableIsSet && activeTab != SubTab.Loading) + { + changeTab = activeTab = SubTab.Loading; + } + else if (!HasRepository && activeTab != SubTab.InitProject && activeTab != SubTab.Settings) + { changeTab = activeTab = SubTab.InitProject; + } + LoadingView.InitializeView(this); HistoryView.InitializeView(this); ChangesView.InitializeView(this); BranchesView.InitializeView(this); @@ -165,12 +176,15 @@ public override void OnUI() { base.OnUI(); - if (HasRepository) - { - DoHeaderGUI(); - } + if(gitExecutableIsSet) + { + if (HasRepository) + { + DoHeaderGUI(); + } - DoToolbarGUI(); + DoToolbarGUI(); + } // GUI for the active tab if (ActiveView != null) @@ -442,6 +456,8 @@ private Subview ToView(SubTab tab) { switch (tab) { + case SubTab.Loading: + return loadingView; case SubTab.InitProject: return initProjectView; case SubTab.History: @@ -457,6 +473,11 @@ private Subview ToView(SubTab tab) } } + public LoadingView LoadingView + { + get { return loadingView; } + } + public HistoryView HistoryView { get { return historyView; } @@ -495,6 +516,7 @@ public override bool IsBusy private enum SubTab { None, + Loading, InitProject, History, Changes, From f627aa5139411881a6c5fb0455d7a3568f11c473 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 28 Dec 2017 18:59:08 -0500 Subject: [PATCH 0022/1008] Properly controlling the activeView while the git path is loading on first run --- .../Extensions/FileSystemExtensions.cs | 4 +++ .../Editor/GitHub.Unity/UI/InitProjectView.cs | 1 + .../Editor/GitHub.Unity/UI/LoadingView.cs | 14 +++++++++- .../Assets/Editor/GitHub.Unity/UI/Window.cs | 27 ++++++++++++++----- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/GitHub.Api/Extensions/FileSystemExtensions.cs b/src/GitHub.Api/Extensions/FileSystemExtensions.cs index 8eb311f6f..69f5a105d 100644 --- a/src/GitHub.Api/Extensions/FileSystemExtensions.cs +++ b/src/GitHub.Api/Extensions/FileSystemExtensions.cs @@ -41,6 +41,8 @@ public static string CalculateFolderMD5(this IFileSystem fileSystem, string path { //https://stackoverflow.com/questions/3625658/creating-hash-for-folder + Logging.Trace("Calculating MD5 for folder: {0}", path); + var filePaths = fileSystem.GetFiles(path, "*", SearchOption.AllDirectories) .OrderBy(p => p) .ToArray(); @@ -62,6 +64,8 @@ public static string CalculateFolderMD5(this IFileSystem fileSystem, string path //Handles empty filePaths case md5.TransformFinalBlock(new byte[0], 0, 0); + Logging.Trace("Completed Calculating MD5 for folder: {0}", path); + return BitConverter.ToString(md5.Hash).Replace("-", "").ToLower(); } } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs index e7c0ca085..dc889436f 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs @@ -23,6 +23,7 @@ public override void InitializeView(IView parent) { base.InitializeView(parent); gitExecutableIsSet = Environment.GitExecutablePath != null; + Redraw(); } public override void OnEnable() diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/LoadingView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/LoadingView.cs index 83a3a3f73..e3676414c 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/LoadingView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/LoadingView.cs @@ -18,7 +18,19 @@ public override void InitializeView(IView parent) public override void OnGUI() { - + GUILayout.BeginVertical(); + { + GUILayout.FlexibleSpace(); + GUILayout.BeginHorizontal(); + { + GUILayout.FlexibleSpace(); + GUILayout.Label(WindowTitle); + GUILayout.FlexibleSpace(); + } + GUILayout.EndHorizontal(); + GUILayout.FlexibleSpace(); + } + GUILayout.EndVertical(); } public override bool IsBusy diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs index 026cd05ab..9ec89ef31 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs @@ -23,8 +23,8 @@ class Window : BaseWindow private const string Window_RepoBranchTooltip = "Active branch"; [NonSerialized] private double notificationClearTime = -1; - [SerializeField] private SubTab changeTab = SubTab.History; - [SerializeField] private SubTab activeTab = SubTab.History; + [SerializeField] private SubTab changeTab = SubTab.None; + [SerializeField] private SubTab activeTab = SubTab.None; [SerializeField] private InitProjectView initProjectView = new InitProjectView(); [SerializeField] private LoadingView loadingView = new LoadingView(); [SerializeField] private BranchesView branchesView = new BranchesView(); @@ -88,13 +88,27 @@ public override void Initialize(IApplicationManager applicationManager) gitExecutableIsSet = Environment.GitExecutablePath != null; - if (!gitExecutableIsSet && activeTab != SubTab.Loading) + if (ApplicationCache.Instance.FirstRun && !gitExecutableIsSet && activeTab != SubTab.Loading) { changeTab = activeTab = SubTab.Loading; } - else if (!HasRepository && activeTab != SubTab.InitProject && activeTab != SubTab.Settings) + else if(gitExecutableIsSet) { - changeTab = activeTab = SubTab.InitProject; + if (HasRepository) + { + if (activeTab == SubTab.Loading) + { + changeTab = SubTab.Changes; + UpdateActiveTab(); + } + } + else + { + if (activeTab != SubTab.InitProject && activeTab != SubTab.Settings) + { + changeTab = activeTab = SubTab.InitProject; + } + } } LoadingView.InitializeView(this); @@ -176,7 +190,7 @@ public override void OnUI() { base.OnUI(); - if(gitExecutableIsSet) + if(ApplicationCache.Instance.FirstRun && gitExecutableIsSet || !ApplicationCache.Instance.FirstRun) { if (HasRepository) { @@ -384,6 +398,7 @@ private void SwitchView(Subview fromView, Subview toView) if (fromView != null) fromView.OnDisable(); + toView.OnEnable(); toView.OnDataUpdate(); From b508a6d708b742b0953463b93f06c09865c32dff Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 29 Dec 2017 12:32:10 -0500 Subject: [PATCH 0023/1008] Adding functionality to perform a file list MD5 Performing a full MD5 on the contents of the zip package takes 1-3s during the startup of Unity. So I changed functionality to perform a full MD5 on the extracted contents and a file list MD5 during application startup. --- .../Extensions/FileSystemExtensions.cs | 11 +- .../Installer/PortableGitInstallTask.cs | 151 +++++++++++------- .../Installer/PortableGitInstallTaskTests.cs | 4 +- 3 files changed, 106 insertions(+), 60 deletions(-) diff --git a/src/GitHub.Api/Extensions/FileSystemExtensions.cs b/src/GitHub.Api/Extensions/FileSystemExtensions.cs index 8eb311f6f..98e447cae 100644 --- a/src/GitHub.Api/Extensions/FileSystemExtensions.cs +++ b/src/GitHub.Api/Extensions/FileSystemExtensions.cs @@ -37,7 +37,7 @@ public static string CalculateFileMD5(this IFileSystem fileSystem, string file) return BitConverter.ToString(computeHash).Replace("-", string.Empty).ToLower(); } - public static string CalculateFolderMD5(this IFileSystem fileSystem, string path) + public static string CalculateFolderMD5(this IFileSystem fileSystem, string path, bool includeContents = true) { //https://stackoverflow.com/questions/3625658/creating-hash-for-folder @@ -54,9 +54,12 @@ public static string CalculateFolderMD5(this IFileSystem fileSystem, string path var pathBytes = Encoding.UTF8.GetBytes(relativeFilePath); md5.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0); - // hash contents - var contentBytes = File.ReadAllBytes(filePath); - md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0); + if (includeContents) + { + // hash contents + var contentBytes = File.ReadAllBytes(filePath); + md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0); + } } //Handles empty filePaths case diff --git a/src/GitHub.Api/Installer/PortableGitInstallTask.cs b/src/GitHub.Api/Installer/PortableGitInstallTask.cs index 4f68d7dee..e4bdefda9 100644 --- a/src/GitHub.Api/Installer/PortableGitInstallTask.cs +++ b/src/GitHub.Api/Installer/PortableGitInstallTask.cs @@ -12,13 +12,17 @@ class PortableGitInstallDetails public NPath GitLfsExecPath { get; } public const string ExtractedMD5 = "65fd0575d3b47d8207b9e19d02faca4f"; + public const string FileListMD5 = "a152a216b2e76f6c127053251187a278"; - private const string ExpectedVersion = "f02737a78695063deace08e96d5042710d3e32db"; + private const string PackageVersion = "f02737a78695063deace08e96d5042710d3e32db"; private const string PackageName = "PortableGit"; - private const string PackageNameWithVersion = PackageName + "_" + ExpectedVersion; + private const string PackageNameWithVersion = PackageName + "_" + PackageVersion; + + private readonly bool onWindows; public PortableGitInstallDetails(NPath targetInstallPath, bool onWindows) { + this.onWindows = onWindows; var gitInstallPath = targetInstallPath.Combine(ApplicationInfo.ApplicationName, PackageNameWithVersion); GitInstallPath = gitInstallPath; @@ -28,7 +32,6 @@ public PortableGitInstallDetails(NPath targetInstallPath, bool onWindows) GitLfsExec += "git-lfs.exe"; GitExecPath = gitInstallPath.Combine("cmd", GitExec); - GitLfsExecPath = gitInstallPath.Combine("mingw32", "libexec", "git-core", GitLfsExec); } else { @@ -36,8 +39,16 @@ public PortableGitInstallDetails(NPath targetInstallPath, bool onWindows) GitLfsExec = "git-lfs"; GitExecPath = gitInstallPath.Combine("bin", GitExec); - GitLfsExecPath = gitInstallPath.Combine("libexec", "git-core", GitLfsExec); } + + GitLfsExecPath = GetGitLfsExecPath(gitInstallPath); + } + + public NPath GetGitLfsExecPath(NPath gitInstallRoot) + { + return onWindows + ? gitInstallRoot.Combine("mingw32", "libexec", "git-core", GitLfsExec) + : gitInstallRoot.Combine("libexec", "git-core", GitLfsExec); } } @@ -64,20 +75,74 @@ protected override NPath RunWithReturn(bool success) return installDetails.GitExecPath; } - var installGit = InstallGit(); - if (installGit) + Token.ThrowIfCancellationRequested(); + + installDetails.GitInstallPath.DeleteIfExists(); + installDetails.GitInstallPath.EnsureParentDirectoryExists(); + + Token.ThrowIfCancellationRequested(); + + var extractTarget = NPath.CreateTempDirectory("git_install_task"); + var installGit = InstallGit(extractTarget); + if (!installGit) + { + Logger.Warning("Failed PortableGitInstallTask"); + return null; + } + + Token.ThrowIfCancellationRequested(); + + var installGitLfs = InstallGitLfs(extractTarget); + if (!installGitLfs) + { + Logger.Warning("Failed PortableGitInstallTask"); + return null; + } + + Token.ThrowIfCancellationRequested(); + + var extractedMD5 = environment.FileSystem.CalculateFolderMD5(extractTarget); + if (!extractedMD5.Equals(PortableGitInstallDetails.ExtractedMD5, StringComparison.InvariantCultureIgnoreCase)) { - var installGitLfs = InstallGitLfs(); - if (installGitLfs) - { - Logger.Trace("Completed PortableGitInstallTask"); - return installDetails.GitExecPath; - } + Logger.Warning("MD5 {0} does not match expected {1}", extractedMD5, PortableGitInstallDetails.ExtractedMD5); + Logger.Warning("Failed PortableGitInstallTask"); + return null; } - Logger.Warning("Unsuccessful PortableGitInstallTask"); + var moveSuccessful = MoveExtractTarget(extractTarget); + if (!moveSuccessful) + { + Logger.Warning("Failed PortableGitInstallTask"); + return null; + } - return null; + Logger.Trace("Completed PortableGitInstallTask"); + return installDetails.GitExecPath; + } + + private bool MoveExtractTarget(NPath extractTarget) + { + try + { + Logger.Trace("Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", extractTarget, + installDetails.GitInstallPath); + + extractTarget.Move(installDetails.GitInstallPath); + + Logger.Trace("Deleting extractTarget:\"{0}\"", extractTarget); + extractTarget.DeleteIfExists(); + + Logger.Trace("Completed PortableGitInstallTask"); + } + catch (Exception ex) + { + Logger.Warning(ex, "Error Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", extractTarget, + installDetails.GitInstallPath); + + return false; + } + + return true; } private bool IsPortableGitExtracted() @@ -88,10 +153,10 @@ private bool IsPortableGitExtracted() return false; } - var installMD5 = environment.FileSystem.CalculateFolderMD5(installDetails.GitInstallPath); - if (!installMD5.Equals(PortableGitInstallDetails.ExtractedMD5, StringComparison.InvariantCultureIgnoreCase)) + var fileListMD5 = environment.FileSystem.CalculateFolderMD5(installDetails.GitInstallPath, false); + if (!fileListMD5.Equals(PortableGitInstallDetails.FileListMD5, StringComparison.InvariantCultureIgnoreCase)) { - Logger.Trace("MD5 {0} does not match expected {1}", installMD5, PortableGitInstallDetails.ExtractedMD5); + Logger.Trace("MD5 {0} does not match expected {1}", fileListMD5, PortableGitInstallDetails.FileListMD5); return false; } @@ -99,11 +164,11 @@ private bool IsPortableGitExtracted() return true; } - private bool InstallGit() + private bool InstallGit(NPath targetPath) { Logger.Trace("InstallGit"); - var tempPath = NPath.GetTempFilename(); + var tempPath = NPath.CreateTempDirectory("git_zip_path"); var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", tempPath, environment); if (!environment.FileSystem.FileExists(gitArchivePath)) @@ -115,54 +180,31 @@ private bool InstallGit() Token.ThrowIfCancellationRequested(); - var tempDirectory = NPath.CreateTempDirectory("git_install_task"); - try { - Logger.Trace("Extracting gitArchivePath:\"{0}\" tempDirectory:\"{1}\"", - gitArchivePath, tempDirectory); + Logger.Trace("Extracting gitArchivePath:\"{0}\" targetPath:\"{1}\"", + gitArchivePath, targetPath); - ZipHelper.ExtractZipFile(gitArchivePath, tempDirectory, Token); + ZipHelper.ExtractZipFile(gitArchivePath, targetPath, Token); } catch (Exception ex) { Logger.Warning(ex, "Error Extracting gitArchivePath:\"{0}\" tempDirectory:\"{1}\"", - gitArchivePath, tempDirectory); + gitArchivePath, targetPath); return false; } - Token.ThrowIfCancellationRequested(); - - try - { - installDetails.GitInstallPath.DeleteIfExists(); - installDetails.GitInstallPath.EnsureParentDirectoryExists(); - - Logger.Trace("Moving tempDirectory:\"{0}\" to gitInstallPath:\"{1}\"", - tempDirectory, installDetails.GitInstallPath); - - tempDirectory.Move(installDetails.GitInstallPath); - } - catch (Exception ex) - { - Logger.Warning(ex, "Error Moving tempDirectory:\"{0}\" to gitInstallPath:\"{1}\"", - tempDirectory, installDetails.GitInstallPath); - - return false; - } - - Logger.Trace("Deleting tempDirectory:\"{0}\"", tempDirectory); - tempDirectory.DeleteIfExists(); + tempPath.DeleteIfExists(); return true; } - private bool InstallGitLfs() + private bool InstallGitLfs(NPath targetPath) { Logger.Trace("InstallGitLfs"); - var tempPath = NPath.GetTempFilename(); + var tempPath = NPath.CreateTempDirectory("git_lfs_zip_path"); var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", tempPath, environment); if (!environment.FileSystem.FileExists(gitLfsArchivePath)) @@ -173,7 +215,7 @@ private bool InstallGitLfs() Token.ThrowIfCancellationRequested(); - var tempDirectory = NPath.CreateTempDirectory("git_install_task"); + var tempDirectory = NPath.CreateTempDirectory("git_lfs_extract_path"); try { @@ -182,7 +224,7 @@ private bool InstallGitLfs() } catch (Exception ex) { - Logger.Warning($"Error Extracting gitLfsArchivePath:\"{gitLfsArchivePath}\" tempDirectory:\"{tempDirectory}\"", ex); + Logger.Warning(ex, $"Error Extracting gitLfsArchivePath:\"{gitLfsArchivePath}\" tempDirectory:\"{tempDirectory}\""); return false; } @@ -190,14 +232,15 @@ private bool InstallGitLfs() var tempDirectoryGitLfsExec = tempDirectory.Combine(installDetails.GitLfsExec); + var targetLfsExecPath = installDetails.GetGitLfsExecPath(targetPath); try { - Logger.Trace("Moving tempDirectoryGitLfsExec:\"{0}\" to gitLfsExecFullPath:\"{1}\"", tempDirectoryGitLfsExec, installDetails.GitLfsExecPath); - tempDirectoryGitLfsExec.Move(installDetails.GitLfsExecPath); + Logger.Trace("Moving tempDirectoryGitLfsExec:\"{0}\" to targetLfsExecPath:\"{1}\"", tempDirectoryGitLfsExec, targetLfsExecPath); + tempDirectoryGitLfsExec.Move(targetLfsExecPath); } catch (Exception ex) { - Logger.Warning($"Error Moving tempDirectoryGitLfsExec:\"{tempDirectoryGitLfsExec}\" to gitLfsExecFullPath:\"{installDetails.GitLfsExecPath}\"", ex); + Logger.Warning(ex, $"Error Moving tempDirectoryGitLfsExec:\"{tempDirectoryGitLfsExec}\" to targetLfsExecPath:\"{targetLfsExecPath}\""); return false; } diff --git a/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs b/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs index a8b2f1fd5..2037a18eb 100644 --- a/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs +++ b/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs @@ -24,8 +24,8 @@ public void GitInstallTest() gitInstallTask.Start().Wait(); - var calculateFolderMd5 = Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath); - calculateFolderMd5.Should().Be(PortableGitInstallDetails.ExtractedMD5); + Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath).Should().Be(PortableGitInstallDetails.ExtractedMD5); + Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath, false).Should().Be(PortableGitInstallDetails.FileListMD5); new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails) .Then(new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails)) From 42e11a617af7c51ff0f01aa6956df8eacba70649 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 29 Dec 2017 14:02:40 -0500 Subject: [PATCH 0024/1008] Removing log message --- src/GitHub.Api/Extensions/FileSystemExtensions.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/GitHub.Api/Extensions/FileSystemExtensions.cs b/src/GitHub.Api/Extensions/FileSystemExtensions.cs index 6f0e9bb6b..98e447cae 100644 --- a/src/GitHub.Api/Extensions/FileSystemExtensions.cs +++ b/src/GitHub.Api/Extensions/FileSystemExtensions.cs @@ -41,8 +41,6 @@ public static string CalculateFolderMD5(this IFileSystem fileSystem, string path { //https://stackoverflow.com/questions/3625658/creating-hash-for-folder - Logging.Trace("Calculating MD5 for folder: {0}", path); - var filePaths = fileSystem.GetFiles(path, "*", SearchOption.AllDirectories) .OrderBy(p => p) .ToArray(); @@ -67,8 +65,6 @@ public static string CalculateFolderMD5(this IFileSystem fileSystem, string path //Handles empty filePaths case md5.TransformFinalBlock(new byte[0], 0, 0); - Logging.Trace("Completed Calculating MD5 for folder: {0}", path); - return BitConverter.ToString(md5.Hash).Replace("-", "").ToLower(); } } From e53178d745a3b1c66154da2daa7b0095090f82c3 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 29 Dec 2017 15:05:40 -0500 Subject: [PATCH 0025/1008] Adding missing file to project --- src/tests/IntegrationTests/IntegrationTests.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/IntegrationTests/IntegrationTests.csproj b/src/tests/IntegrationTests/IntegrationTests.csproj index 4c8d3da01..121e2dc04 100644 --- a/src/tests/IntegrationTests/IntegrationTests.csproj +++ b/src/tests/IntegrationTests/IntegrationTests.csproj @@ -87,6 +87,7 @@ + From 524c4789d71284f840ff893e5c45fe252f48da87 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 29 Dec 2017 15:05:58 -0500 Subject: [PATCH 0026/1008] Fixing test --- src/tests/IntegrationTests/UnzipTaskTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/IntegrationTests/UnzipTaskTests.cs b/src/tests/IntegrationTests/UnzipTaskTests.cs index 3abc9a07b..e33677741 100644 --- a/src/tests/IntegrationTests/UnzipTaskTests.cs +++ b/src/tests/IntegrationTests/UnzipTaskTests.cs @@ -19,13 +19,13 @@ public void UnzipTest() var cacheContainer = Substitute.For(); Environment = new IntegrationTestEnvironment(cacheContainer, TestBasePath, SolutionDirectory); - var archiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", TestBasePath.Combine("gip_zip_extracted"), Environment); + var destinationPath = TestBasePath.Combine("git_zip").CreateDirectory(); + var archiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", destinationPath, Environment); Logger.Trace("ArchiveFilePath: {0}", archiveFilePath); Logger.Trace("TestBasePath: {0}", TestBasePath); - var extractedPath = TestBasePath.Combine("git_zip_extracted"); - extractedPath.CreateDirectory(); + var extractedPath = TestBasePath.Combine("git_zip_extracted").CreateDirectory(); var zipProgress = 0; Logger.Trace("Pct Complete {0}%", zipProgress); From 971640a6be24b81ce064c5718098733059192720 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 29 Dec 2017 15:11:39 -0500 Subject: [PATCH 0027/1008] Being more speicifc about usage --- src/GitHub.Api/Extensions/FileSystemExtensions.cs | 15 --------------- src/GitHub.Api/Installer/GitInstaller.cs | 2 +- src/tests/IntegrationTests/Git/GitSetupTests.cs | 6 +++--- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/src/GitHub.Api/Extensions/FileSystemExtensions.cs b/src/GitHub.Api/Extensions/FileSystemExtensions.cs index 8eb311f6f..4953cf96d 100644 --- a/src/GitHub.Api/Extensions/FileSystemExtensions.cs +++ b/src/GitHub.Api/Extensions/FileSystemExtensions.cs @@ -8,21 +8,6 @@ namespace GitHub.Unity { static class FileSystemExtensions { - public static string CalculateMD5(this IFileSystem fileSystem, string path) - { - if (fileSystem.DirectoryExists(path)) - { - return fileSystem.CalculateFolderMD5(path); - } - - if (fileSystem.FileExists(path)) - { - return fileSystem.CalculateFileMD5(path); - } - - throw new ArgumentException($@"Path does not exist: ""{path}"""); - } - public static string CalculateFileMD5(this IFileSystem fileSystem, string file) { byte[] computeHash; diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index f54765298..b2d76dfc5 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -96,7 +96,7 @@ public bool IsGitLfsExtracted() return false; } - var calculateMd5 = environment.FileSystem.CalculateMD5(GitLfsExecutablePath); + var calculateMd5 = (string)environment.FileSystem.CalculateFileMD5((string)GitLfsExecutablePath); logger.Trace("GitLFS MD5: {0}", calculateMd5); var md5 = environment.IsWindows ? WindowsGitLfsExecutableMD5 : MacGitLfsExecutableMD5; if (String.Compare(calculateMd5, md5, true) != 0) diff --git a/src/tests/IntegrationTests/Git/GitSetupTests.cs b/src/tests/IntegrationTests/Git/GitSetupTests.cs index 1a18cdc8b..73651d020 100644 --- a/src/tests/IntegrationTests/Git/GitSetupTests.cs +++ b/src/tests/IntegrationTests/Git/GitSetupTests.cs @@ -41,7 +41,7 @@ public async Task InstallGit() gitLfsDestinationPath = gitLfsDestinationPath.Combine("libexec", "git-core", "git-lfs.exe"); gitLfsDestinationPath.FileExists().Should().BeTrue(); - var calculateMd5 = NPath.FileSystem.CalculateMD5(gitLfsDestinationPath); + var calculateMd5 = (string)NPath.FileSystem.CalculateFileMD5((string)gitLfsDestinationPath); Assert.IsTrue(string.Compare(calculateMd5, GitInstaller.WindowsGitLfsExecutableMD5, true) == 0); setupDone = await gitSetup.SetupIfNeeded(new Progress(x => percent = x)); @@ -83,7 +83,7 @@ public void VerifyWindowsGitLfsBundle() gitLfsPath.Exists().Should().BeTrue(); - var calculateMd5 = NPath.FileSystem.CalculateMD5(gitLfsPath); + var calculateMd5 = (string)NPath.FileSystem.CalculateFileMD5((string)gitLfsPath); calculateMd5.ToLower().Should().Be(GitInstaller.WindowsGitLfsExecutableMD5.ToLower()); } @@ -103,7 +103,7 @@ public void VerifyMacGitLfsBundle() gitLfsPath.Exists().Should().BeTrue(); - var calculateMd5 = NPath.FileSystem.CalculateMD5(gitLfsPath); + var calculateMd5 = (string)NPath.FileSystem.CalculateFileMD5((string)gitLfsPath); calculateMd5.ToLower().Should().Be(GitInstaller.MacGitLfsExecutableMD5.ToLower()); } } From b778c9ed4603a11498623674248c4627725304c5 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 29 Dec 2017 15:38:25 -0500 Subject: [PATCH 0028/1008] Adding missing redraw --- .../Assets/Editor/GitHub.Unity/UI/InitProjectView.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs index e7c0ca085..dc889436f 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs @@ -23,6 +23,7 @@ public override void InitializeView(IView parent) { base.InitializeView(parent); gitExecutableIsSet = Environment.GitExecutablePath != null; + Redraw(); } public override void OnEnable() From 002ca60efe213bc8dd79ea5c7194ea39521c8ba6 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 29 Dec 2017 15:41:05 -0500 Subject: [PATCH 0029/1008] Fixing spelling --- GitHub.Unity.sln.DotSettings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GitHub.Unity.sln.DotSettings b/GitHub.Unity.sln.DotSettings index 50b26bf2b..31c5e56f1 100644 --- a/GitHub.Unity.sln.DotSettings +++ b/GitHub.Unity.sln.DotSettings @@ -335,7 +335,7 @@ </TypePattern> </Patterns> ID - ME + MD SSH <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> From ad927a67b76e35113c33f592b685028edf1122bd Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 29 Dec 2017 16:42:37 -0500 Subject: [PATCH 0030/1008] Adding a task to download the contents of a text file --- src/GitHub.Api/Tasks/DownloadTask.cs | 52 +++++++++++++++++-- .../Download/DownloadTaskTests.cs | 11 ++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 159b2be61..d98825d81 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Net; +using System.Text; using System.Threading; namespace GitHub.Unity @@ -100,7 +101,7 @@ public static WebResponse GetResponseWithoutException(this WebRequest request) } } - class DownloadTask: TaskBase + class DownloadTask : TaskBase { private IFileSystem fileSystem; private long bytes; @@ -121,10 +122,11 @@ public DownloadTask(CancellationToken token, IFileSystem fileSystem, string url, protected override DownloadResult RunWithReturn(bool success) { base.RunWithReturn(success); - + RaiseOnStart(); - var downloadResult = new DownloadResult { + var downloadResult = new DownloadResult + { Url = Url, Destination = Destination }; @@ -213,10 +215,10 @@ public bool Download() } } - var responseLength = webResponse.ContentLength; + var responseLength = webResponse.ContentLength; if (restarted && bytes > 0) { - UpdateProgress(bytes / (float) responseLength); + UpdateProgress(bytes / (float)responseLength); } using (var responseStream = webResponse.GetResponseStream()) @@ -236,4 +238,44 @@ public bool Download() protected string Destination { get; } } + + class DownloadTextTask : TaskBase + { + public float Progress { get; set; } + + public DownloadTextTask(CancellationToken token, string url) + : base(token) + { + Url = url; + Name = "DownloadTask"; + } + + protected override string RunWithReturn(bool success) + { + base.RunWithReturn(success); + + RaiseOnStart(); + + var webRequest = WebRequest.Create(Url); + webRequest.Method = "GET"; + webRequest.Timeout = 3000; + + using (var webResponse = (HttpWebResponse) webRequest.GetResponseWithoutException()) + { + var webResponseCharacterSet = webResponse.CharacterSet ?? Encoding.UTF8.BodyName; + var encoding = Encoding.GetEncoding(webResponseCharacterSet); + + using (var responseStream = webResponse.GetResponseStream()) + using (var reader = new StreamReader(responseStream, encoding)) + return reader.ReadToEnd(); + } + } + + protected virtual void UpdateProgress(float progress) + { + Progress = progress; + } + + protected string Url { get; } + } } diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 2e237defe..b10a4ffb6 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -49,5 +49,16 @@ public async Task TestDownloadTask() downloadResult.MD5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); } + + [Test] + public void TestDownloadTextTask() + { + InitializeTaskManager(); + + var downloadTask = new DownloadTextTask(CancellationToken.None, "https://github.com/robots.txt"); + var result = downloadTask.Start().Result; + var resultLines = result.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); + resultLines[0].Should().Be("# If you would like to crawl GitHub contact us at support@github.com."); + } } } From 8c3db7152b92ac0bd7a368dbfd49f4bb4758468a Mon Sep 17 00:00:00 2001 From: Miguel Piedrafita Date: Mon, 1 Jan 2018 00:31:10 +0100 Subject: [PATCH 0031/1008] Update license year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 32e3acbc9..9f06ebe84 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2016 GitHub +Copyright (c) 2016-2018 GitHub Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 117a44d84d7c1169dbccabc6c3fa0bf227358730 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 09:29:28 -0500 Subject: [PATCH 0032/1008] Removing download result object --- src/GitHub.Api/Tasks/DownloadTask.cs | 21 ++++--------------- .../Download/DownloadTaskTests.cs | 10 +++++---- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index d98825d81..ccfea82f2 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -75,17 +75,6 @@ public static bool Copy(Stream source, Stream destination, int chunkSize, long t } } - public class DownloadResult - { - public bool Success { get; set; } - - public string Url { get; set; } - - public string Destination { get; set; } - - public string MD5Sum { get; set; } - } - public static class WebRequestExtensions { public static WebResponse GetResponseWithoutException(this WebRequest request) @@ -101,7 +90,7 @@ public static WebResponse GetResponseWithoutException(this WebRequest request) } } - class DownloadTask : TaskBase + class DownloadTask : TaskBase { private IFileSystem fileSystem; private long bytes; @@ -119,9 +108,9 @@ public DownloadTask(CancellationToken token, IFileSystem fileSystem, string url, Name = "DownloadTask"; } - protected override DownloadResult RunWithReturn(bool success) + protected override void Run(bool success) { - base.RunWithReturn(success); + base.Run(success); RaiseOnStart(); @@ -144,10 +133,8 @@ protected override DownloadResult RunWithReturn(bool success) } finally { - RaiseOnEnd(downloadResult); + RaiseOnEnd(); } - - return downloadResult; } protected virtual void UpdateProgress(float progress) diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index b10a4ffb6..c0a629dbf 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -26,12 +26,13 @@ public async Task TestDownloadTask() var downloadHalfPath = TestBasePath.Combine("5MB-split.zip"); var downloadTask = new DownloadTask(CancellationToken.None, fileSystem, TestDownload, downloadPath); - var downloadResult = await downloadTask.StartAwait(); + await downloadTask.StartAwait(); var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); Logger.Trace("File size {0} bytes", downloadPathBytes.Length); - downloadResult.MD5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); + var md5Sum = fileSystem.CalculateMD5(downloadPath); + md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); var random = new Random(); var takeCount = random.Next(downloadPathBytes.Length); @@ -42,12 +43,13 @@ public async Task TestDownloadTask() fileSystem.WriteAllBytes(downloadHalfPath, cutDownloadPathBytes); downloadTask = new DownloadTask(CancellationToken.None, fileSystem, TestDownload, downloadHalfPath); - downloadResult = await downloadTask.StartAwait(); + await downloadTask.StartAwait(); var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadHalfPath); Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); - downloadResult.MD5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); + md5Sum = fileSystem.CalculateMD5(downloadPath); + md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); } [Test] From 3c1f6a7623c86d342379da36ee65c19149a9e3b0 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 09:40:20 -0500 Subject: [PATCH 0033/1008] Returning successful result --- src/GitHub.Api/Tasks/DownloadTask.cs | 22 ++++++++----------- .../Download/DownloadTaskTests.cs | 8 +++++-- src/tests/IntegrationTests/SetUpFixture.cs | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index ccfea82f2..bcaf1e5f3 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -90,7 +90,7 @@ public static WebResponse GetResponseWithoutException(this WebRequest request) } } - class DownloadTask : TaskBase + class DownloadTask : TaskBase { private IFileSystem fileSystem; private long bytes; @@ -108,22 +108,16 @@ public DownloadTask(CancellationToken token, IFileSystem fileSystem, string url, Name = "DownloadTask"; } - protected override void Run(bool success) + protected override bool RunWithReturn(bool success) { - base.Run(success); + base.RunWithReturn(success); RaiseOnStart(); - var downloadResult = new DownloadResult - { - Url = Url, - Destination = Destination - }; - + var result = false; try { - downloadResult.Success = Download(); - downloadResult.MD5Sum = fileSystem.CalculateMD5(Destination); + result = Download(); } catch (Exception ex) { @@ -133,8 +127,10 @@ protected override void Run(bool success) } finally { - RaiseOnEnd(); + RaiseOnEnd(result); } + + return result; } protected virtual void UpdateProgress(float progress) @@ -144,7 +140,7 @@ protected virtual void UpdateProgress(float progress) public bool Download() { - FileInfo fileInfo = new FileInfo(Destination); + var fileInfo = new FileInfo(Destination); if (fileSystem.FileExists(Destination)) { var fileLength = fileSystem.FileLength(Destination); diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index c0a629dbf..90f332ab4 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -26,7 +26,9 @@ public async Task TestDownloadTask() var downloadHalfPath = TestBasePath.Combine("5MB-split.zip"); var downloadTask = new DownloadTask(CancellationToken.None, fileSystem, TestDownload, downloadPath); - await downloadTask.StartAwait(); + var downloadResult = await downloadTask.StartAwait(); + + downloadResult.Should().BeTrue(); var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); Logger.Trace("File size {0} bytes", downloadPathBytes.Length); @@ -43,7 +45,9 @@ public async Task TestDownloadTask() fileSystem.WriteAllBytes(downloadHalfPath, cutDownloadPathBytes); downloadTask = new DownloadTask(CancellationToken.None, fileSystem, TestDownload, downloadHalfPath); - await downloadTask.StartAwait(); + downloadResult = await downloadTask.StartAwait(); + + downloadResult.Should().BeTrue(); var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadHalfPath); Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); diff --git a/src/tests/IntegrationTests/SetUpFixture.cs b/src/tests/IntegrationTests/SetUpFixture.cs index 21c14f375..62793030c 100644 --- a/src/tests/IntegrationTests/SetUpFixture.cs +++ b/src/tests/IntegrationTests/SetUpFixture.cs @@ -14,7 +14,7 @@ public void Setup() Logging.LogAdapter = new MultipleLogAdapter( new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-integration-tests.log") - //, new ConsoleLogAdapter() + , new ConsoleLogAdapter() ); } } From 3efdcb8cf92ac427ef4abb31a32fd1127ac3710e Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 09:41:51 -0500 Subject: [PATCH 0034/1008] Fixes needed after merge --- src/GitHub.Api/IO/IFileSystem.cs | 1 - src/tests/IntegrationTests/Download/DownloadTaskTests.cs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/GitHub.Api/IO/IFileSystem.cs b/src/GitHub.Api/IO/IFileSystem.cs index 80afb8467..5955e623f 100644 --- a/src/GitHub.Api/IO/IFileSystem.cs +++ b/src/GitHub.Api/IO/IFileSystem.cs @@ -44,6 +44,5 @@ public interface IFileSystem char DirectorySeparatorChar { get; } bool ExistingPathIsDirectory(string path); void SetCurrentDirectory(string currentDirectory); - byte[] ReadAllBytes(string path); } } \ No newline at end of file diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 90f332ab4..a67b4c5df 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -33,7 +33,7 @@ public async Task TestDownloadTask() var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); Logger.Trace("File size {0} bytes", downloadPathBytes.Length); - var md5Sum = fileSystem.CalculateMD5(downloadPath); + var md5Sum = fileSystem.CalculateFileMD5(downloadPath); md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); var random = new Random(); @@ -52,7 +52,7 @@ public async Task TestDownloadTask() var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadHalfPath); Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); - md5Sum = fileSystem.CalculateMD5(downloadPath); + md5Sum = fileSystem.CalculateFileMD5(downloadPath); md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); } From 2fb124e65f54164aa8f23e5135b56a486eacf7ee Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 09:51:38 -0500 Subject: [PATCH 0035/1008] Making sure all paths get deleted --- .../Installer/PortableGitInstallTask.cs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/GitHub.Api/Installer/PortableGitInstallTask.cs b/src/GitHub.Api/Installer/PortableGitInstallTask.cs index e4bdefda9..0accf1d3d 100644 --- a/src/GitHub.Api/Installer/PortableGitInstallTask.cs +++ b/src/GitHub.Api/Installer/PortableGitInstallTask.cs @@ -168,8 +168,8 @@ private bool InstallGit(NPath targetPath) { Logger.Trace("InstallGit"); - var tempPath = NPath.CreateTempDirectory("git_zip_path"); - var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", tempPath, environment); + var tempZipPath = NPath.CreateTempDirectory("git_zip_path"); + var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", tempZipPath, environment); if (!environment.FileSystem.FileExists(gitArchivePath)) { @@ -195,7 +195,7 @@ private bool InstallGit(NPath targetPath) return false; } - tempPath.DeleteIfExists(); + tempZipPath.DeleteIfExists(); return true; } @@ -204,8 +204,8 @@ private bool InstallGitLfs(NPath targetPath) { Logger.Trace("InstallGitLfs"); - var tempPath = NPath.CreateTempDirectory("git_lfs_zip_path"); - var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", tempPath, environment); + var tempZipPath = NPath.CreateTempDirectory("git_lfs_zip_path"); + var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", tempZipPath, environment); if (!environment.FileSystem.FileExists(gitLfsArchivePath)) { @@ -215,22 +215,22 @@ private bool InstallGitLfs(NPath targetPath) Token.ThrowIfCancellationRequested(); - var tempDirectory = NPath.CreateTempDirectory("git_lfs_extract_path"); + var tempZipExtractPath = NPath.CreateTempDirectory("git_lfs_extract_path"); try { - Logger.Trace("Extracting gitLfsArchivePath:\"{0}\" tempDirectory:\"{1}\"", gitLfsArchivePath, tempDirectory); - ZipHelper.ExtractZipFile(gitLfsArchivePath, tempDirectory, Token); + Logger.Trace("Extracting gitLfsArchivePath:\"{0}\" tempDirectory:\"{1}\"", gitLfsArchivePath, tempZipExtractPath); + ZipHelper.ExtractZipFile(gitLfsArchivePath, tempZipExtractPath, Token); } catch (Exception ex) { - Logger.Warning(ex, $"Error Extracting gitLfsArchivePath:\"{gitLfsArchivePath}\" tempDirectory:\"{tempDirectory}\""); + Logger.Warning(ex, $"Error Extracting gitLfsArchivePath:\"{gitLfsArchivePath}\" tempDirectory:\"{tempZipExtractPath}\""); return false; } Token.ThrowIfCancellationRequested(); - var tempDirectoryGitLfsExec = tempDirectory.Combine(installDetails.GitLfsExec); + var tempDirectoryGitLfsExec = tempZipExtractPath.Combine(installDetails.GitLfsExec); var targetLfsExecPath = installDetails.GetGitLfsExecPath(targetPath); try @@ -244,8 +244,9 @@ private bool InstallGitLfs(NPath targetPath) return false; } - Logger.Trace("Deleting tempDirectory:\"{0}\"", tempDirectory); - tempDirectory.DeleteIfExists(); + tempZipPath.DeleteIfExists(); + tempZipExtractPath.DeleteIfExists(); + return true; } } From 295e4268b929a1b9789ad5182d11f045a29150db Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 11:31:41 -0500 Subject: [PATCH 0036/1008] Specifying the archive path to PortableGitInstallTask --- .../Installer/PortableGitInstallTask.cs | 16 +++++----------- .../Installer/PortableGitInstallTaskTests.cs | 10 +++++++--- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/GitHub.Api/Installer/PortableGitInstallTask.cs b/src/GitHub.Api/Installer/PortableGitInstallTask.cs index 0accf1d3d..769dd81b3 100644 --- a/src/GitHub.Api/Installer/PortableGitInstallTask.cs +++ b/src/GitHub.Api/Installer/PortableGitInstallTask.cs @@ -56,10 +56,14 @@ class PortableGitInstallTask : TaskBase { private readonly PortableGitInstallDetails installDetails; private readonly IEnvironment environment; + private readonly string gitArchivePath; + private readonly string gitLfsArchivePath; - public PortableGitInstallTask(CancellationToken token, IEnvironment environment, PortableGitInstallDetails installDetails) : base(token) + public PortableGitInstallTask(CancellationToken token, IEnvironment environment, string gitArchivePath, string gitLfsArchivePath, PortableGitInstallDetails installDetails) : base(token) { this.environment = environment; + this.gitArchivePath = gitArchivePath; + this.gitLfsArchivePath = gitLfsArchivePath; this.installDetails = installDetails; } @@ -168,9 +172,6 @@ private bool InstallGit(NPath targetPath) { Logger.Trace("InstallGit"); - var tempZipPath = NPath.CreateTempDirectory("git_zip_path"); - var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", tempZipPath, environment); - if (!environment.FileSystem.FileExists(gitArchivePath)) { Logger.Warning("Archive \"{0}\" missing", gitArchivePath); @@ -195,8 +196,6 @@ private bool InstallGit(NPath targetPath) return false; } - tempZipPath.DeleteIfExists(); - return true; } @@ -204,9 +203,6 @@ private bool InstallGitLfs(NPath targetPath) { Logger.Trace("InstallGitLfs"); - var tempZipPath = NPath.CreateTempDirectory("git_lfs_zip_path"); - var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", tempZipPath, environment); - if (!environment.FileSystem.FileExists(gitLfsArchivePath)) { Logger.Warning($"Archive \"{gitLfsArchivePath}\" missing"); @@ -243,8 +239,6 @@ private bool InstallGitLfs(NPath targetPath) Logger.Warning(ex, $"Error Moving tempDirectoryGitLfsExec:\"{tempDirectoryGitLfsExec}\" to targetLfsExecPath:\"{targetLfsExecPath}\""); return false; } - - tempZipPath.DeleteIfExists(); tempZipExtractPath.DeleteIfExists(); return true; diff --git a/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs b/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs index 2037a18eb..848660cd9 100644 --- a/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs +++ b/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs @@ -19,16 +19,20 @@ public void GitInstallTest() var gitInstallationPath = TestBasePath.Combine("GitInstall").CreateDirectory(); + var zipArchivesPath = TestBasePath.Combine("ZipArchives").CreateDirectory(); + var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); + var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); + var gitInstallDetails = new PortableGitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows); - var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails); + var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, gitArchivePath, gitLfsArchivePath, gitInstallDetails); gitInstallTask.Start().Wait(); Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath).Should().Be(PortableGitInstallDetails.ExtractedMD5); Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath, false).Should().Be(PortableGitInstallDetails.FileListMD5); - new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails) - .Then(new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails)) + new PortableGitInstallTask(CancellationToken.None, Environment, gitArchivePath, gitLfsArchivePath, gitInstallDetails) + .Then(new PortableGitInstallTask(CancellationToken.None, Environment, gitArchivePath, gitLfsArchivePath, gitInstallDetails)) .Start() .Wait(); } From c9eeccbcb05fb435bb4e2c39f3f8f36661d50086 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 11:32:29 -0500 Subject: [PATCH 0037/1008] Restricting type of ShortCircuitTask to nullable value --- src/GitHub.Api/Installer/ShortCircuitTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitHub.Api/Installer/ShortCircuitTask.cs b/src/GitHub.Api/Installer/ShortCircuitTask.cs index c925fb2ec..996d6eb19 100644 --- a/src/GitHub.Api/Installer/ShortCircuitTask.cs +++ b/src/GitHub.Api/Installer/ShortCircuitTask.cs @@ -3,7 +3,7 @@ namespace GitHub.Unity { - class ShortCircuitTask : TaskBase + class ShortCircuitTask : TaskBase where TResult : class { private readonly Func action; From cf872fdd29695d4bff8244b458b9e4ddf2aef874 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 12:10:59 -0500 Subject: [PATCH 0038/1008] Providing the git install details from ApplicationManagerBase --- .../Application/ApplicationManagerBase.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 9d1e0ffd1..0e5bcd422 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -88,9 +88,9 @@ private ITask SetupGit() }); } - private TaskBase BuildDetermineGitPathTask() + private ITask BuildDetermineGitPathTask() { - TaskBase determinePath = new FuncTask(CancellationToken, () => { + ITask determinePath = new FuncTask(CancellationToken, () => { if (Environment.GitExecutablePath != null) { return Environment.GitExecutablePath; @@ -111,9 +111,19 @@ private TaskBase BuildDetermineGitPathTask() { var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); var installDetails = new PortableGitInstallDetails(applicationDataPath, true); - var installTask = new PortableGitInstallTask(CancellationToken, Environment, installDetails); - determinePath = determinePath.Then(new ShortCircuitTask(CancellationToken, installTask)); + var zipArchivesPath = NPath.CreateTempDirectory("portable_git_zip").CreateDirectory(); + var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); + var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); + + var installTask = new PortableGitInstallTask(CancellationToken, Environment, gitArchivePath, gitLfsArchivePath, installDetails); + + determinePath = determinePath + .Then(new ShortCircuitTask(CancellationToken, installTask)) + .Then((b, path) => { + zipArchivesPath.DeleteIfExists(); + return path; + }); } if (!environmentIsWindows) From 2800d7f07f4f79e9cb60de94a11bf43123206bd4 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 15:01:43 -0500 Subject: [PATCH 0039/1008] Adding functionality to validate the downloaded files md5 and retrying --- src/GitHub.Api/Tasks/DownloadTask.cs | 33 +++++++++++++++++-- .../Download/DownloadTaskTests.cs | 2 +- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index bcaf1e5f3..1702546b1 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -92,17 +92,19 @@ public static WebResponse GetResponseWithoutException(this WebRequest request) class DownloadTask : TaskBase { - private IFileSystem fileSystem; + private readonly IFileSystem fileSystem; private long bytes; private WebRequest webRequest; private bool restarted; public float Progress { get; set; } - public DownloadTask(CancellationToken token, IFileSystem fileSystem, string url, string destination) + public DownloadTask(CancellationToken token, IFileSystem fileSystem, string url, string destination, string validationHash = null, int retryCount = 0) : base(token) { this.fileSystem = fileSystem; + ValidationHash = validationHash; + RetryCount = retryCount; Url = url; Destination = destination; Name = "DownloadTask"; @@ -115,9 +117,30 @@ protected override bool RunWithReturn(bool success) RaiseOnStart(); var result = false; + var attempts = 0; try { - result = Download(); + do + { + Logger.Trace($"Download of {Url} to {Destination} Attempt {attempts + 1} of {RetryCount + 1}"); + result = Download(); + if (result && ValidationHash != null) + { + var md5 = fileSystem.CalculateMD5(Destination); + result = md5.Equals(ValidationHash, StringComparison.CurrentCultureIgnoreCase); + + if (!result) + { + Logger.Warning($"Downloaded MD5 {md5} does not match expected. Deleting {Destination}."); + fileSystem.FileDelete(Destination); + } + else + { + Logger.Trace($"Download confirmed {md5}"); + break; + } + } + } while (RetryCount < attempts++); } catch (Exception ex) { @@ -220,6 +243,10 @@ public bool Download() protected string Url { get; } protected string Destination { get; } + + protected string ValidationHash { get; } + + protected int RetryCount { get; } } class DownloadTextTask : TaskBase diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 90f332ab4..d11612c56 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -44,7 +44,7 @@ public async Task TestDownloadTask() var cutDownloadPathBytes = downloadPathBytes.Take(takeCount).ToArray(); fileSystem.WriteAllBytes(downloadHalfPath, cutDownloadPathBytes); - downloadTask = new DownloadTask(CancellationToken.None, fileSystem, TestDownload, downloadHalfPath); + downloadTask = new DownloadTask(CancellationToken.None, fileSystem, TestDownload, downloadHalfPath, TestDownloadMD5, 1); downloadResult = await downloadTask.StartAwait(); downloadResult.Should().BeTrue(); From 2d4ad861c232270895ab32951e778f4e02cce779 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 15:20:03 -0500 Subject: [PATCH 0040/1008] Starting to configure download tasks to work as expected --- .../Application/ApplicationManagerBase.cs | 28 +++++++++++++++++-- src/GitHub.Api/Tasks/DownloadTask.cs | 4 +-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 0e5bcd422..1fc22fa33 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -113,8 +113,32 @@ private ITask BuildDetermineGitPathTask() var installDetails = new PortableGitInstallDetails(applicationDataPath, true); var zipArchivesPath = NPath.CreateTempDirectory("portable_git_zip").CreateDirectory(); - var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); - var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); + var gitArchivePath = zipArchivesPath.Combine("git.zip"); + var gitLfsArchivePath = zipArchivesPath.Combine("git-lfs.zip"); + + // var zipArchivesPath = NPath.CreateTempDirectory("portable_git_zip").CreateDirectory(); + // var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); + // var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); + + var downloadGitMd5Task = new DownloadTextTask(CancellationToken, + "https://github-vs-s3.amazonaws.com/github-vs/unity/portable_git/git.zip.MD5"); + + var downloadGitTask = new DownloadTask(CancellationToken, Environment.FileSystem, + "https://github-vs-s3.amazonaws.com/github-vs/unity/portable_git/git.zip", gitArchivePath, retryCount: 1); + + downloadGitTask = downloadGitMd5Task + .Then((b, s) => { downloadGitTask.ValidationHash = s; }) + .Then(downloadGitTask); + + var downloadGitLfsMd5Task = new DownloadTextTask(CancellationToken, + "https://github-vs-s3.amazonaws.com/github-vs/unity/portable_git/git-lfs.zip.MD5"); + + var downloadGitLfsTask = new DownloadTask(CancellationToken, Environment.FileSystem, + "https://github-vs-s3.amazonaws.com/github-vs/unity/portable_git/git-lfs.zip", gitLfsArchivePath); + + downloadGitLfsMd5Task.Then((b, s) => { + downloadGitTask.ValidationHash = s; + }).Then(downloadGitTask); var installTask = new PortableGitInstallTask(CancellationToken, Environment, gitArchivePath, gitLfsArchivePath, installDetails); diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 1702546b1..1173ab62c 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -126,7 +126,7 @@ protected override bool RunWithReturn(bool success) result = Download(); if (result && ValidationHash != null) { - var md5 = fileSystem.CalculateMD5(Destination); + var md5 = fileSystem.CalculateFileMD5(Destination); result = md5.Equals(ValidationHash, StringComparison.CurrentCultureIgnoreCase); if (!result) @@ -244,7 +244,7 @@ public bool Download() protected string Destination { get; } - protected string ValidationHash { get; } + public string ValidationHash { get; set; } protected int RetryCount { get; } } From 28a741b84c50e8f8d44abee3646be3c0e99424d7 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 15:52:36 -0500 Subject: [PATCH 0041/1008] Better to throw an exception when things don't work out --- src/GitHub.Api/Tasks/DownloadTask.cs | 80 ++++++++++--------- .../Download/DownloadTaskTests.cs | 38 +++++++-- 2 files changed, 73 insertions(+), 45 deletions(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 1702546b1..be7d739e7 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -90,11 +90,10 @@ public static WebResponse GetResponseWithoutException(this WebRequest request) } } - class DownloadTask : TaskBase + class DownloadTask : TaskBase { private readonly IFileSystem fileSystem; private long bytes; - private WebRequest webRequest; private bool restarted; public float Progress { get; set; } @@ -110,19 +109,19 @@ public DownloadTask(CancellationToken token, IFileSystem fileSystem, string url, Name = "DownloadTask"; } - protected override bool RunWithReturn(bool success) + protected override void Run(bool success) { - base.RunWithReturn(success); + base.Run(success); RaiseOnStart(); - var result = false; var attempts = 0; try { + bool result; do { - Logger.Trace($"Download of {Url} to {Destination} Attempt {attempts + 1} of {RetryCount + 1}"); + Logger.Trace($"Download of {Url} Attempt {attempts + 1} of {RetryCount + 1}"); result = Download(); if (result && ValidationHash != null) { @@ -140,20 +139,23 @@ protected override bool RunWithReturn(bool success) break; } } - } while (RetryCount < attempts++); + } while (attempts++ < RetryCount); + + if (!result) + { + throw new DownloadException("Error downloading file"); + } } catch (Exception ex) { Errors = ex.Message; - if (!RaiseFaultHandlers(ex)) + if (!RaiseFaultHandlers(new DownloadException("Error downloading file", ex))) throw; } finally { - RaiseOnEnd(result); + RaiseOnEnd(); } - - return result; } protected virtual void UpdateProgress(float progress) @@ -178,51 +180,42 @@ public bool Download() } } - webRequest = WebRequest.Create(Url); - var httpWebRequest = webRequest as HttpWebRequest; - if (httpWebRequest != null) + var expectingResume = restarted && bytes > 0; + + var webRequest = (HttpWebRequest)WebRequest.Create(Url); + + if (expectingResume) { - if (bytes > 0) - { - // TODO: fix classlibs to take long overloads - httpWebRequest.AddRange((int)bytes); - } + // TODO: fix classlibs to take long overloads + webRequest.AddRange((int)bytes); } webRequest.Method = "GET"; webRequest.Timeout = 3000; - if (restarted && bytes > 0) + if (expectingResume) Logger.Trace($"Resuming download of {Url} to {Destination}"); else Logger.Trace($"Downloading {Url} to {Destination}"); - using (var webResponse = webRequest.GetResponseWithoutException()) + using (var webResponse = (HttpWebResponse) webRequest.GetResponseWithoutException()) { - if (webResponse == null) - return false; + var httpStatusCode = webResponse.StatusCode; + Logger.Trace($"Downloading {Url} StatusCode:{(int)webResponse.StatusCode}"); - if (restarted && bytes > 0) + if (expectingResume && httpStatusCode == HttpStatusCode.RequestedRangeNotSatisfiable) { - var httpWebResponse = webResponse as HttpWebResponse; - if (httpWebResponse != null) - { - var httpStatusCode = httpWebResponse.StatusCode; - if (httpStatusCode == HttpStatusCode.RequestedRangeNotSatisfiable) - { - UpdateProgress(1); - return true; - } + UpdateProgress(1); + return true; + } - if (!(httpStatusCode == HttpStatusCode.OK || httpStatusCode == HttpStatusCode.PartialContent)) - { - return false; - } - } + if (!(httpStatusCode == HttpStatusCode.OK || httpStatusCode == HttpStatusCode.PartialContent)) + { + return false; } var responseLength = webResponse.ContentLength; - if (restarted && bytes > 0) + if (expectingResume) { UpdateProgress(bytes / (float)responseLength); } @@ -249,6 +242,15 @@ public bool Download() protected int RetryCount { get; } } + class DownloadException : Exception + { + public DownloadException(string message) : base(message) + { } + + public DownloadException(string message, Exception innerException) : base(message, innerException) + { } + } + class DownloadTextTask : TaskBase { public float Progress { get; set; } diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index d11612c56..9dc131baa 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -26,9 +26,7 @@ public async Task TestDownloadTask() var downloadHalfPath = TestBasePath.Combine("5MB-split.zip"); var downloadTask = new DownloadTask(CancellationToken.None, fileSystem, TestDownload, downloadPath); - var downloadResult = await downloadTask.StartAwait(); - - downloadResult.Should().BeTrue(); + await downloadTask.StartAwait(); var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); Logger.Trace("File size {0} bytes", downloadPathBytes.Length); @@ -45,9 +43,7 @@ public async Task TestDownloadTask() fileSystem.WriteAllBytes(downloadHalfPath, cutDownloadPathBytes); downloadTask = new DownloadTask(CancellationToken.None, fileSystem, TestDownload, downloadHalfPath, TestDownloadMD5, 1); - downloadResult = await downloadTask.StartAwait(); - - downloadResult.Should().BeTrue(); + await downloadTask.StartAwait(); var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadHalfPath); Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); @@ -56,6 +52,36 @@ public async Task TestDownloadTask() md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); } + [Test] + public void TestDownloadFailure() + { + InitializeTaskManager(); + + var fileSystem = new FileSystem(); + + var downloadPath = TestBasePath.Combine("5MB.zip"); + + var taskFailed = false; + Exception exceptionThrown = null; + + var autoResetEvent = new AutoResetEvent(false); + + var downloadTask = new DownloadTask(CancellationToken.None, fileSystem, "http://www.unknown.com/5MB.gz", downloadPath, null, 1) + .Finally((b, exception) => { + taskFailed = !b; + exceptionThrown = exception; + autoResetEvent.Set(); + }); + + downloadTask.Start(); + + autoResetEvent.WaitOne(); + + taskFailed.Should().BeTrue(); + exceptionThrown.Should().NotBeNull(); + } + + [Test] public void TestDownloadTextTask() { From fc941f0a673f01ab7885253e5f14cab897b755e6 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 16:02:28 -0500 Subject: [PATCH 0042/1008] Fixing test base class --- src/tests/IntegrationTests/BasePlatformIntegrationTest.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs index c8c6e6d27..47815c17c 100644 --- a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs +++ b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs @@ -31,7 +31,12 @@ protected void InitializePlatform(NPath repoPath, NPath environmentPath, bool en { var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); var installDetails = new PortableGitInstallDetails(applicationDataPath, true); - var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, installDetails); + + var zipArchivesPath = TestBasePath.Combine("ZipArchives").CreateDirectory(); + var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); + var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); + + var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, gitArchivePath, gitLfsArchivePath, installDetails); var installPath = gitInstallTask.Start().Result; Environment.GitExecutablePath = installPath; From 5f5af7655c685d31b9a58ce0e20b0f74d32c4745 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 16:03:55 -0500 Subject: [PATCH 0043/1008] Download functionality that is not working presently --- .../Application/ApplicationManagerBase.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 1fc22fa33..f1309ace0 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -116,10 +116,6 @@ private ITask BuildDetermineGitPathTask() var gitArchivePath = zipArchivesPath.Combine("git.zip"); var gitLfsArchivePath = zipArchivesPath.Combine("git-lfs.zip"); - // var zipArchivesPath = NPath.CreateTempDirectory("portable_git_zip").CreateDirectory(); - // var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); - // var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); - var downloadGitMd5Task = new DownloadTextTask(CancellationToken, "https://github-vs-s3.amazonaws.com/github-vs/unity/portable_git/git.zip.MD5"); @@ -136,11 +132,12 @@ private ITask BuildDetermineGitPathTask() var downloadGitLfsTask = new DownloadTask(CancellationToken, Environment.FileSystem, "https://github-vs-s3.amazonaws.com/github-vs/unity/portable_git/git-lfs.zip", gitLfsArchivePath); - downloadGitLfsMd5Task.Then((b, s) => { - downloadGitTask.ValidationHash = s; - }).Then(downloadGitTask); + downloadGitLfsTask = downloadGitLfsMd5Task.Then((b, s) => { + downloadGitLfsTask.ValidationHash = s; + }).Then(downloadGitLfsTask); - var installTask = new PortableGitInstallTask(CancellationToken, Environment, gitArchivePath, gitLfsArchivePath, installDetails); + var installTask = downloadGitTask.Then(downloadGitLfsTask) + .Then(new PortableGitInstallTask(CancellationToken, Environment, gitArchivePath, gitLfsArchivePath, installDetails)); determinePath = determinePath .Then(new ShortCircuitTask(CancellationToken, installTask)) From c2f2859e980d895681e0d46aa04ea5192a655fdc Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 2 Jan 2018 16:59:58 -0500 Subject: [PATCH 0044/1008] Setting up a download sequence to show it works --- src/GitHub.Api/Tasks/DownloadTask.cs | 44 +++++++++++----- .../Download/DownloadTaskTests.cs | 52 +++++++++++++++++++ 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index be7d739e7..2f5e7b59a 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -130,7 +130,7 @@ protected override void Run(bool success) if (!result) { - Logger.Warning($"Downloaded MD5 {md5} does not match expected. Deleting {Destination}."); + Logger.Warning($"Downloaded MD5 {md5} does not match {ValidationHash}. Deleting {Destination}."); fileSystem.FileDelete(Destination); } else @@ -237,7 +237,7 @@ public bool Download() protected string Destination { get; } - protected string ValidationHash { get; } + public string ValidationHash { get; set; } protected int RetryCount { get; } } @@ -264,23 +264,41 @@ public DownloadTextTask(CancellationToken token, string url) protected override string RunWithReturn(bool success) { - base.RunWithReturn(success); + var result = base.RunWithReturn(success); RaiseOnStart(); - var webRequest = WebRequest.Create(Url); - webRequest.Method = "GET"; - webRequest.Timeout = 3000; - - using (var webResponse = (HttpWebResponse) webRequest.GetResponseWithoutException()) + try { - var webResponseCharacterSet = webResponse.CharacterSet ?? Encoding.UTF8.BodyName; - var encoding = Encoding.GetEncoding(webResponseCharacterSet); + Logger.Trace($"Downloading {Url}"); + var webRequest = WebRequest.Create(Url); + webRequest.Method = "GET"; + webRequest.Timeout = 3000; - using (var responseStream = webResponse.GetResponseStream()) - using (var reader = new StreamReader(responseStream, encoding)) - return reader.ReadToEnd(); + using (var webResponse = (HttpWebResponse)webRequest.GetResponseWithoutException()) + { + var webResponseCharacterSet = webResponse.CharacterSet ?? Encoding.UTF8.BodyName; + var encoding = Encoding.GetEncoding(webResponseCharacterSet); + + using (var responseStream = webResponse.GetResponseStream()) + using (var reader = new StreamReader(responseStream, encoding)) + { + result = reader.ReadToEnd(); + } + } + } + catch (Exception ex) + { + Errors = ex.Message; + if (!RaiseFaultHandlers(new DownloadException("Error downloading text", ex))) + throw; } + finally + { + RaiseOnEnd(result); + } + + return result; } protected virtual void UpdateProgress(float progress) diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 9dc131baa..3b5787580 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -92,5 +92,57 @@ public void TestDownloadTextTask() var resultLines = result.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); resultLines[0].Should().Be("# If you would like to crawl GitHub contact us at support@github.com."); } + + [Test] + public void TestDownloadFileAndHash() + { + InitializeTaskManager(); + + var gitArchivePath = TestBasePath.Combine("git.zip"); + var gitLfsArchivePath = TestBasePath.Combine("git-lfs.zip"); + + var fileSystem = new FileSystem(); + + var downloadGitMd5Task = new DownloadTextTask(CancellationToken.None, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt?cb=1"); + + var downloadGitTask = new DownloadTask(CancellationToken.None, fileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip", gitArchivePath, retryCount: 1); + + var downloadGitLfsMd5Task = new DownloadTextTask(CancellationToken.None, + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt?cb=1"); + + var downloadGitLfsTask = new DownloadTask(CancellationToken.None, fileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip", gitLfsArchivePath, retryCount: 1); + + var result = true; + Exception exception = null; + + var autoResetEvent = new AutoResetEvent(false); + + downloadGitMd5Task + .Then((b, s) => + { + downloadGitTask.ValidationHash = s; + }) + .Then(downloadGitTask) + .Then(downloadGitLfsMd5Task) + .Then((b, s) => + { + downloadGitLfsTask.ValidationHash = s; + }) + .Then(downloadGitLfsTask) + .Finally((b, ex) => { + result = b; + exception = ex; + autoResetEvent.Set(); + }) + .Start(); + + autoResetEvent.WaitOne(); + + result.Should().BeTrue(); + exception.Should().BeNull(); + } } } From 6aa10da969bc7bead1c43cce2c16a4841ab057c5 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 3 Jan 2018 11:57:07 -0500 Subject: [PATCH 0045/1008] The functionality I would like to work --- .../Application/ApplicationManagerBase.cs | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index f1309ace0..c395fb396 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -116,27 +116,30 @@ private ITask BuildDetermineGitPathTask() var gitArchivePath = zipArchivesPath.Combine("git.zip"); var gitLfsArchivePath = zipArchivesPath.Combine("git-lfs.zip"); - var downloadGitMd5Task = new DownloadTextTask(CancellationToken, - "https://github-vs-s3.amazonaws.com/github-vs/unity/portable_git/git.zip.MD5"); + var downloadGitMd5Task = new DownloadTextTask(CancellationToken.None, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt?cb=1"); - var downloadGitTask = new DownloadTask(CancellationToken, Environment.FileSystem, - "https://github-vs-s3.amazonaws.com/github-vs/unity/portable_git/git.zip", gitArchivePath, retryCount: 1); + var downloadGitTask = new DownloadTask(CancellationToken.None, Environment.FileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip", gitArchivePath, retryCount: 1); - downloadGitTask = downloadGitMd5Task - .Then((b, s) => { downloadGitTask.ValidationHash = s; }) - .Then(downloadGitTask); + var downloadGitLfsMd5Task = new DownloadTextTask(CancellationToken.None, + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt?cb=1"); - var downloadGitLfsMd5Task = new DownloadTextTask(CancellationToken, - "https://github-vs-s3.amazonaws.com/github-vs/unity/portable_git/git-lfs.zip.MD5"); + var downloadGitLfsTask = new DownloadTask(CancellationToken.None, Environment.FileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip", gitLfsArchivePath, retryCount: 1); - var downloadGitLfsTask = new DownloadTask(CancellationToken, Environment.FileSystem, - "https://github-vs-s3.amazonaws.com/github-vs/unity/portable_git/git-lfs.zip", gitLfsArchivePath); - - downloadGitLfsTask = downloadGitLfsMd5Task.Then((b, s) => { - downloadGitLfsTask.ValidationHash = s; - }).Then(downloadGitLfsTask); - - var installTask = downloadGitTask.Then(downloadGitLfsTask) + var installTask = downloadGitMd5Task + .Then((b, s) => + { + downloadGitTask.ValidationHash = s; + }) + .Then(downloadGitTask) + .Then(downloadGitLfsMd5Task) + .Then((b, s) => + { + downloadGitLfsTask.ValidationHash = s; + }) + .Then(downloadGitLfsTask) .Then(new PortableGitInstallTask(CancellationToken, Environment, gitArchivePath, gitLfsArchivePath, installDetails)); determinePath = determinePath From 08719d9390e727e38ee87f7394968e0aef766719 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 3 Jan 2018 15:59:32 -0500 Subject: [PATCH 0046/1008] Ideas --- src/GitHub.Api/Application/ApplicationManagerBase.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 9d1e0ffd1..7c880c680 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -48,10 +48,13 @@ public void Run(bool firstRun) { Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory); - SetupGit() - .Then(RestartRepository) - .ThenInUI(InitializeUI) - .Start(); + var afterGitSetup = new ActionTask(CancellationToken, RestartRepository) + .ThenInUI(InitializeUI); + +// SetupGit() +// .Then(RestartRepository) +// .ThenInUI(InitializeUI) +// .Start(); } private ITask SetupGit() From fa746614d27580126a07f75ede853c6a6b249586 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 3 Jan 2018 16:02:05 -0500 Subject: [PATCH 0047/1008] Fix Resharper abbreviation --- GitHub.Unity.sln.DotSettings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GitHub.Unity.sln.DotSettings b/GitHub.Unity.sln.DotSettings index ce5e4a30b..31c5e56f1 100644 --- a/GitHub.Unity.sln.DotSettings +++ b/GitHub.Unity.sln.DotSettings @@ -335,7 +335,7 @@ </TypePattern> </Patterns> ID - MD5 + MD SSH <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> From c9784c7ab708a6000f712409014684e6db15fb77 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 3 Jan 2018 18:42:48 -0500 Subject: [PATCH 0048/1008] Stacking tasks in order to get the desired async forks --- .../Application/ApplicationManagerBase.cs | 61 ++++++++++++- src/GitHub.Api/GitHub.Api.csproj | 1 + src/GitHub.Api/Installer/GitInstaller.cs | 87 +++++++++++++++++++ .../Installer/PortableGitInstallTask.cs | 25 ------ 4 files changed, 145 insertions(+), 29 deletions(-) create mode 100644 src/GitHub.Api/Installer/GitInstaller.cs diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 7c880c680..f8bc914e7 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -51,10 +51,63 @@ public void Run(bool firstRun) var afterGitSetup = new ActionTask(CancellationToken, RestartRepository) .ThenInUI(InitializeUI); -// SetupGit() -// .Then(RestartRepository) -// .ThenInUI(InitializeUI) -// .Start(); + Logger.Trace("afterGitSetup"); + + var windowsCredentialSetup = new ActionTask(CancellationToken, () => { + GitClient.GetConfig("credential.helper", GitConfigSource.Global).Then((b, credentialHelper) => { + if (!string.IsNullOrEmpty(credentialHelper)) + { + Logger.Trace("Windows CredentialHelper: {0}", credentialHelper); + afterGitSetup.Start(); + } + else + { + Logger.Warning("No Windows CredentialHeloper found: Setting to wincred"); + + GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global) + .Then(() => { afterGitSetup.Start(); }).Start(); + } + }).Start(); + }); + + Logger.Trace("windowsCredentialSetup"); + + var afterPathDetermined = new ActionTask(CancellationToken, (b1, path) => { + + Logger.Trace("Setting Environment git path: {0}", path); + Environment.GitExecutablePath = path; + + }).ThenInUI(() => { + + Environment.User.Initialize(GitClient); + + if (Environment.IsWindows) + { + windowsCredentialSetup.Start(); + } + else + { + afterGitSetup.Start(); + } + }); + + Logger.Trace("afterPathDetermined"); + + var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); + var installDetails = new PortableGitInstallDetails(applicationDataPath, true); + + var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails); + gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken, (b, s) => { + + Logger.Trace("Success: {0}", s); + + new FuncTask(CancellationToken, () => s) + .Then(afterPathDetermined) + .Start(); + + }), new ActionTask(CancellationToken, () => { + Logger.Trace("Failure"); + }) ); } private ITask SetupGit() diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 6b96d5c11..3f2c2842f 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -117,6 +117,7 @@ + diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs new file mode 100644 index 000000000..4d8c5334d --- /dev/null +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -0,0 +1,87 @@ +using System; +using System.Threading; + +namespace GitHub.Unity +{ + class GitInstaller + { + private static ILogging Logger = Logging.GetLogger(); + + private readonly IEnvironment environment; + private readonly IZipHelper sharpZipLibHelper; + private readonly CancellationToken cancellationToken; + private readonly PortableGitInstallDetails installDetails; + + public GitInstaller(IEnvironment environment, CancellationToken cancellationToken, PortableGitInstallDetails installDetails) + : this(environment, null, cancellationToken, installDetails) + { + } + + public GitInstaller(IEnvironment environment, IZipHelper sharpZipLibHelper, CancellationToken cancellationToken, PortableGitInstallDetails installDetails) + { + this.environment = environment; + this.sharpZipLibHelper = sharpZipLibHelper; + this.cancellationToken = cancellationToken; + this.installDetails = installDetails; + } + + public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) + { + Logger.Trace("SetupGitIfNeeded"); + + if (!environment.IsWindows) + { + onFailure.Start(); + } + + new FuncTask(cancellationToken, IsPortableGitExtracted) + .Then((success, isPortableGitExtracted) => { + + Logger.Trace("IsPortableGitExtracted: {0}", isPortableGitExtracted); + + if (isPortableGitExtracted) + { + new FuncTask(cancellationToken, () => installDetails.GitExecPath) + .Then(onSuccess) + .Start(); + } + else + { + new PortableGitInstallTask(cancellationToken, environment, installDetails).Then((b, path) => { + if (b && path != null) + { + new FuncTask(cancellationToken, () => path) + .Then(onSuccess) + .Start(); + } + else + { + onFailure.Start(); + } + }).Start(); + + } + + }).Start(); + } + + private bool IsPortableGitExtracted() + { + if (!installDetails.GitInstallPath.DirectoryExists()) + { + Logger.Trace("{0} does not exist", installDetails.GitInstallPath); + return false; + } + + var fileListMD5 = environment.FileSystem.CalculateFolderMD5(installDetails.GitInstallPath, false); + if (!fileListMD5.Equals(PortableGitInstallDetails.FileListMD5, StringComparison.InvariantCultureIgnoreCase)) + { + Logger.Trace("MD5 {0} does not match expected {1}", fileListMD5, PortableGitInstallDetails.FileListMD5); + return false; + } + + Logger.Trace("Git Present"); + return true; + } + } +} diff --git a/src/GitHub.Api/Installer/PortableGitInstallTask.cs b/src/GitHub.Api/Installer/PortableGitInstallTask.cs index 0accf1d3d..f419706e7 100644 --- a/src/GitHub.Api/Installer/PortableGitInstallTask.cs +++ b/src/GitHub.Api/Installer/PortableGitInstallTask.cs @@ -69,12 +69,6 @@ protected override NPath RunWithReturn(bool success) Logger.Trace("Starting PortableGitInstallTask"); - if (IsPortableGitExtracted()) - { - Logger.Trace("Completed PortableGitInstallTask"); - return installDetails.GitExecPath; - } - Token.ThrowIfCancellationRequested(); installDetails.GitInstallPath.DeleteIfExists(); @@ -145,25 +139,6 @@ private bool MoveExtractTarget(NPath extractTarget) return true; } - private bool IsPortableGitExtracted() - { - if (!installDetails.GitInstallPath.DirectoryExists()) - { - Logger.Trace("{0} does not exist", installDetails.GitInstallPath); - return false; - } - - var fileListMD5 = environment.FileSystem.CalculateFolderMD5(installDetails.GitInstallPath, false); - if (!fileListMD5.Equals(PortableGitInstallDetails.FileListMD5, StringComparison.InvariantCultureIgnoreCase)) - { - Logger.Trace("MD5 {0} does not match expected {1}", fileListMD5, PortableGitInstallDetails.FileListMD5); - return false; - } - - Logger.Trace("Git Present"); - return true; - } - private bool InstallGit(NPath targetPath) { Logger.Trace("InstallGit"); From 06fac2e4a89cfa5b12b96ecc2871d0157e465be2 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 3 Jan 2018 19:11:05 -0500 Subject: [PATCH 0049/1008] Rebuilding the GitInstaller --- .../Application/ApplicationManagerBase.cs | 4 +- src/GitHub.Api/GitHub.Api.csproj | 1 - src/GitHub.Api/Installer/GitInstaller.cs | 126 ++++++++-- .../Installer/PortableGitInstallTask.cs | 228 ------------------ src/GitHub.Api/Installer/UnzipTask.cs | 5 +- .../BasePlatformIntegrationTest.cs | 2 +- .../Installer/GitInstallerTests.cs | 36 +++ .../Installer/PortableGitInstallTaskTests.cs | 36 --- .../IntegrationTests/IntegrationTests.csproj | 2 +- 9 files changed, 147 insertions(+), 293 deletions(-) delete mode 100644 src/GitHub.Api/Installer/PortableGitInstallTask.cs create mode 100644 src/tests/IntegrationTests/Installer/GitInstallerTests.cs delete mode 100644 src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index f8bc914e7..fac8e4710 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -94,7 +94,7 @@ public void Run(bool firstRun) Logger.Trace("afterPathDetermined"); var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); - var installDetails = new PortableGitInstallDetails(applicationDataPath, true); + var installDetails = new GitInstallDetails(applicationDataPath, true); var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails); gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken, (b, s) => { @@ -166,7 +166,7 @@ private TaskBase BuildDetermineGitPathTask() if (environmentIsWindows) { var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); - var installDetails = new PortableGitInstallDetails(applicationDataPath, true); + var installDetails = new GitInstallDetails(applicationDataPath, true); var installTask = new PortableGitInstallTask(CancellationToken, Environment, installDetails); determinePath = determinePath.Then(new ShortCircuitTask(CancellationToken, installTask)); diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 3f2c2842f..5eeb6655a 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -118,7 +118,6 @@ - diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 4d8c5334d..80fbb4b01 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -3,6 +3,55 @@ namespace GitHub.Unity { + class GitInstallDetails + { + public NPath GitInstallPath { get; } + public string GitExec { get; } + public NPath GitExecPath { get; } + public string GitLfsExec { get; } + public NPath GitLfsExecPath { get; } + + public const string ExtractedMD5 = "65fd0575d3b47d8207b9e19d02faca4f"; + public const string FileListMD5 = "a152a216b2e76f6c127053251187a278"; + + private const string PackageVersion = "f02737a78695063deace08e96d5042710d3e32db"; + private const string PackageName = "PortableGit"; + private const string PackageNameWithVersion = PackageName + "_" + PackageVersion; + + private readonly bool onWindows; + + public GitInstallDetails(NPath targetInstallPath, bool onWindows) + { + this.onWindows = onWindows; + var gitInstallPath = targetInstallPath.Combine(ApplicationInfo.ApplicationName, PackageNameWithVersion); + GitInstallPath = gitInstallPath; + + if (onWindows) + { + GitExec += "git.exe"; + GitLfsExec += "git-lfs.exe"; + + GitExecPath = gitInstallPath.Combine("cmd", GitExec); + } + else + { + GitExec = "git"; + GitLfsExec = "git-lfs"; + + GitExecPath = gitInstallPath.Combine("bin", GitExec); + } + + GitLfsExecPath = GetGitLfsExecPath(gitInstallPath); + } + + public NPath GetGitLfsExecPath(NPath gitInstallRoot) + { + return onWindows + ? gitInstallRoot.Combine("mingw32", "libexec", "git-core", GitLfsExec) + : gitInstallRoot.Combine("libexec", "git-core", GitLfsExec); + } + } + class GitInstaller { private static ILogging Logger = Logging.GetLogger(); @@ -10,14 +59,14 @@ class GitInstaller private readonly IEnvironment environment; private readonly IZipHelper sharpZipLibHelper; private readonly CancellationToken cancellationToken; - private readonly PortableGitInstallDetails installDetails; + private readonly GitInstallDetails installDetails; - public GitInstaller(IEnvironment environment, CancellationToken cancellationToken, PortableGitInstallDetails installDetails) - : this(environment, null, cancellationToken, installDetails) + public GitInstaller(IEnvironment environment, CancellationToken cancellationToken, GitInstallDetails installDetails) + : this(environment, ZipHelper.Instance, cancellationToken, installDetails) { } - public GitInstaller(IEnvironment environment, IZipHelper sharpZipLibHelper, CancellationToken cancellationToken, PortableGitInstallDetails installDetails) + public GitInstaller(IEnvironment environment, IZipHelper sharpZipLibHelper, CancellationToken cancellationToken, GitInstallDetails installDetails) { this.environment = environment; this.sharpZipLibHelper = sharpZipLibHelper; @@ -34,38 +83,73 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) onFailure.Start(); } - new FuncTask(cancellationToken, IsPortableGitExtracted) + new FuncTask(cancellationToken, IsGitExtracted) .Then((success, isPortableGitExtracted) => { Logger.Trace("IsPortableGitExtracted: {0}", isPortableGitExtracted); if (isPortableGitExtracted) { + Logger.Trace("SetupGitIfNeeded: Skipped"); + new FuncTask(cancellationToken, () => installDetails.GitExecPath) .Then(onSuccess) .Start(); } else { - new PortableGitInstallTask(cancellationToken, environment, installDetails).Then((b, path) => { - if (b && path != null) - { - new FuncTask(cancellationToken, () => path) - .Then(onSuccess) - .Start(); - } - else - { - onFailure.Start(); - } - }).Start(); - + var tempZipPath = NPath.CreateTempDirectory("git_zip_paths"); + var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", tempZipPath, environment); + var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", tempZipPath, environment); + + var gitExtractPath = tempZipPath.Combine("git").CreateDirectory(); + var gitLfsExtractPath = tempZipPath.Combine("git-lfs").CreateDirectory(); + + new UnzipTask(cancellationToken, gitArchivePath, gitExtractPath, sharpZipLibHelper) + .Then(new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper)) + .Then(() => { + var targetGitLfsExecPath = installDetails.GetGitLfsExecPath(gitExtractPath); + var extractGitLfsExePath = gitLfsExtractPath.Combine(installDetails.GitLfsExec); + extractGitLfsExePath.Move(targetGitLfsExecPath); + + var extractedMD5 = environment.FileSystem.CalculateFolderMD5(gitExtractPath); + if (!extractedMD5.Equals(GitInstallDetails.ExtractedMD5, StringComparison.InvariantCultureIgnoreCase)) + { + Logger.Warning("MD5 {0} does not match expected {1}", extractedMD5, GitInstallDetails.ExtractedMD5); + Logger.Warning("Failed PortableGitInstallTask"); + throw new Exception(); + } + + Logger.Trace("Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", gitExtractPath, + installDetails.GitInstallPath); + + gitExtractPath.Move(installDetails.GitInstallPath); + + Logger.Trace("Deleting tempZipPath:\"{0}\"", tempZipPath); + tempZipPath.DeleteIfExists(); + + }).Finally((b, exception) => { + if (b) + { + Logger.Trace("SetupGitIfNeeded: Success"); + + new FuncTask(cancellationToken, () => installDetails.GitExecPath) + .Then(onSuccess) + .Start(); + } + else + { + Logger.Trace("SetupGitIfNeeded: Failed"); + + onFailure.Start(); + } + }).Start(); } }).Start(); } - private bool IsPortableGitExtracted() + private bool IsGitExtracted() { if (!installDetails.GitInstallPath.DirectoryExists()) { @@ -74,9 +158,9 @@ private bool IsPortableGitExtracted() } var fileListMD5 = environment.FileSystem.CalculateFolderMD5(installDetails.GitInstallPath, false); - if (!fileListMD5.Equals(PortableGitInstallDetails.FileListMD5, StringComparison.InvariantCultureIgnoreCase)) + if (!fileListMD5.Equals(GitInstallDetails.FileListMD5, StringComparison.InvariantCultureIgnoreCase)) { - Logger.Trace("MD5 {0} does not match expected {1}", fileListMD5, PortableGitInstallDetails.FileListMD5); + Logger.Trace("MD5 {0} does not match expected {1}", fileListMD5, GitInstallDetails.FileListMD5); return false; } diff --git a/src/GitHub.Api/Installer/PortableGitInstallTask.cs b/src/GitHub.Api/Installer/PortableGitInstallTask.cs deleted file mode 100644 index f419706e7..000000000 --- a/src/GitHub.Api/Installer/PortableGitInstallTask.cs +++ /dev/null @@ -1,228 +0,0 @@ -using System; -using System.Threading; - -namespace GitHub.Unity -{ - class PortableGitInstallDetails - { - public NPath GitInstallPath { get; } - public string GitExec { get; } - public NPath GitExecPath { get; } - public string GitLfsExec { get; } - public NPath GitLfsExecPath { get; } - - public const string ExtractedMD5 = "65fd0575d3b47d8207b9e19d02faca4f"; - public const string FileListMD5 = "a152a216b2e76f6c127053251187a278"; - - private const string PackageVersion = "f02737a78695063deace08e96d5042710d3e32db"; - private const string PackageName = "PortableGit"; - private const string PackageNameWithVersion = PackageName + "_" + PackageVersion; - - private readonly bool onWindows; - - public PortableGitInstallDetails(NPath targetInstallPath, bool onWindows) - { - this.onWindows = onWindows; - var gitInstallPath = targetInstallPath.Combine(ApplicationInfo.ApplicationName, PackageNameWithVersion); - GitInstallPath = gitInstallPath; - - if (onWindows) - { - GitExec += "git.exe"; - GitLfsExec += "git-lfs.exe"; - - GitExecPath = gitInstallPath.Combine("cmd", GitExec); - } - else - { - GitExec = "git"; - GitLfsExec = "git-lfs"; - - GitExecPath = gitInstallPath.Combine("bin", GitExec); - } - - GitLfsExecPath = GetGitLfsExecPath(gitInstallPath); - } - - public NPath GetGitLfsExecPath(NPath gitInstallRoot) - { - return onWindows - ? gitInstallRoot.Combine("mingw32", "libexec", "git-core", GitLfsExec) - : gitInstallRoot.Combine("libexec", "git-core", GitLfsExec); - } - } - - class PortableGitInstallTask : TaskBase - { - private readonly PortableGitInstallDetails installDetails; - private readonly IEnvironment environment; - - public PortableGitInstallTask(CancellationToken token, IEnvironment environment, PortableGitInstallDetails installDetails) : base(token) - { - this.environment = environment; - this.installDetails = installDetails; - } - - protected override NPath RunWithReturn(bool success) - { - base.RunWithReturn(success); - - Logger.Trace("Starting PortableGitInstallTask"); - - Token.ThrowIfCancellationRequested(); - - installDetails.GitInstallPath.DeleteIfExists(); - installDetails.GitInstallPath.EnsureParentDirectoryExists(); - - Token.ThrowIfCancellationRequested(); - - var extractTarget = NPath.CreateTempDirectory("git_install_task"); - var installGit = InstallGit(extractTarget); - if (!installGit) - { - Logger.Warning("Failed PortableGitInstallTask"); - return null; - } - - Token.ThrowIfCancellationRequested(); - - var installGitLfs = InstallGitLfs(extractTarget); - if (!installGitLfs) - { - Logger.Warning("Failed PortableGitInstallTask"); - return null; - } - - Token.ThrowIfCancellationRequested(); - - var extractedMD5 = environment.FileSystem.CalculateFolderMD5(extractTarget); - if (!extractedMD5.Equals(PortableGitInstallDetails.ExtractedMD5, StringComparison.InvariantCultureIgnoreCase)) - { - Logger.Warning("MD5 {0} does not match expected {1}", extractedMD5, PortableGitInstallDetails.ExtractedMD5); - Logger.Warning("Failed PortableGitInstallTask"); - return null; - } - - var moveSuccessful = MoveExtractTarget(extractTarget); - if (!moveSuccessful) - { - Logger.Warning("Failed PortableGitInstallTask"); - return null; - } - - Logger.Trace("Completed PortableGitInstallTask"); - return installDetails.GitExecPath; - } - - private bool MoveExtractTarget(NPath extractTarget) - { - try - { - Logger.Trace("Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", extractTarget, - installDetails.GitInstallPath); - - extractTarget.Move(installDetails.GitInstallPath); - - Logger.Trace("Deleting extractTarget:\"{0}\"", extractTarget); - extractTarget.DeleteIfExists(); - - Logger.Trace("Completed PortableGitInstallTask"); - } - catch (Exception ex) - { - Logger.Warning(ex, "Error Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", extractTarget, - installDetails.GitInstallPath); - - return false; - } - - return true; - } - - private bool InstallGit(NPath targetPath) - { - Logger.Trace("InstallGit"); - - var tempZipPath = NPath.CreateTempDirectory("git_zip_path"); - var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", tempZipPath, environment); - - if (!environment.FileSystem.FileExists(gitArchivePath)) - { - Logger.Warning("Archive \"{0}\" missing", gitArchivePath); - - return false; - } - - Token.ThrowIfCancellationRequested(); - - try - { - Logger.Trace("Extracting gitArchivePath:\"{0}\" targetPath:\"{1}\"", - gitArchivePath, targetPath); - - ZipHelper.ExtractZipFile(gitArchivePath, targetPath, Token); - } - catch (Exception ex) - { - Logger.Warning(ex, "Error Extracting gitArchivePath:\"{0}\" tempDirectory:\"{1}\"", - gitArchivePath, targetPath); - - return false; - } - - tempZipPath.DeleteIfExists(); - - return true; - } - - private bool InstallGitLfs(NPath targetPath) - { - Logger.Trace("InstallGitLfs"); - - var tempZipPath = NPath.CreateTempDirectory("git_lfs_zip_path"); - var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", tempZipPath, environment); - - if (!environment.FileSystem.FileExists(gitLfsArchivePath)) - { - Logger.Warning($"Archive \"{gitLfsArchivePath}\" missing"); - return false; - } - - Token.ThrowIfCancellationRequested(); - - var tempZipExtractPath = NPath.CreateTempDirectory("git_lfs_extract_path"); - - try - { - Logger.Trace("Extracting gitLfsArchivePath:\"{0}\" tempDirectory:\"{1}\"", gitLfsArchivePath, tempZipExtractPath); - ZipHelper.ExtractZipFile(gitLfsArchivePath, tempZipExtractPath, Token); - } - catch (Exception ex) - { - Logger.Warning(ex, $"Error Extracting gitLfsArchivePath:\"{gitLfsArchivePath}\" tempDirectory:\"{tempZipExtractPath}\""); - return false; - } - - Token.ThrowIfCancellationRequested(); - - var tempDirectoryGitLfsExec = tempZipExtractPath.Combine(installDetails.GitLfsExec); - - var targetLfsExecPath = installDetails.GetGitLfsExecPath(targetPath); - try - { - Logger.Trace("Moving tempDirectoryGitLfsExec:\"{0}\" to targetLfsExecPath:\"{1}\"", tempDirectoryGitLfsExec, targetLfsExecPath); - tempDirectoryGitLfsExec.Move(targetLfsExecPath); - } - catch (Exception ex) - { - Logger.Warning(ex, $"Error Moving tempDirectoryGitLfsExec:\"{tempDirectoryGitLfsExec}\" to targetLfsExecPath:\"{targetLfsExecPath}\""); - return false; - } - - tempZipPath.DeleteIfExists(); - tempZipExtractPath.DeleteIfExists(); - - return true; - } - } -} \ No newline at end of file diff --git a/src/GitHub.Api/Installer/UnzipTask.cs b/src/GitHub.Api/Installer/UnzipTask.cs index 7478deb6f..ac832944b 100644 --- a/src/GitHub.Api/Installer/UnzipTask.cs +++ b/src/GitHub.Api/Installer/UnzipTask.cs @@ -38,12 +38,11 @@ protected override void Run(bool success) private void UnzipArchive() { - Logger.Trace("Zip File: {0}", archiveFilePath); - Logger.Trace("Target Path: {0}", extractedPath); + Logger.Trace("Unzip File: {0} to Path: {1}", archiveFilePath, extractedPath); zipHelper.Extract(archiveFilePath, extractedPath, Token, zipFileProgress, estimatedDurationProgress); - Logger.Trace("Completed"); + Logger.Trace("Completed Unzip"); } } } diff --git a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs index c8c6e6d27..8a137ae6d 100644 --- a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs +++ b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs @@ -30,7 +30,7 @@ protected void InitializePlatform(NPath repoPath, NPath environmentPath, bool en if (setupGit) { var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); - var installDetails = new PortableGitInstallDetails(applicationDataPath, true); + var installDetails = new GitInstallDetails(applicationDataPath, true); var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, installDetails); var installPath = gitInstallTask.Start().Result; diff --git a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs new file mode 100644 index 000000000..870094948 --- /dev/null +++ b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs @@ -0,0 +1,36 @@ +using System.Threading; +using FluentAssertions; +using GitHub.Unity; +using NSubstitute; +using NUnit.Framework; + +namespace IntegrationTests +{ + [TestFixture] + class GitInstallerTests : BaseTaskManagerTest + { + [Test] + public void GitInstallTest() + { + InitializeTaskManager(); + + var cacheContainer = Substitute.For(); + Environment = new IntegrationTestEnvironment(cacheContainer, TestBasePath, SolutionDirectory, enableTrace: true); + + var gitInstallationPath = TestBasePath.Combine("GitInstall").CreateDirectory(); + + var gitInstallDetails = new GitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows); +// var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails); +// +// gitInstallTask.Start().Wait(); +// +// Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath).Should().Be(PortableGitInstallDetails.ExtractedMD5); +// Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath, false).Should().Be(PortableGitInstallDetails.FileListMD5); +// +// new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails) +// .Then(new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails)) +// .Start() +// .Wait(); + } + } +} \ No newline at end of file diff --git a/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs b/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs deleted file mode 100644 index 2037a18eb..000000000 --- a/src/tests/IntegrationTests/Installer/PortableGitInstallTaskTests.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Threading; -using FluentAssertions; -using GitHub.Unity; -using NSubstitute; -using NUnit.Framework; - -namespace IntegrationTests -{ - [TestFixture] - class PortableGitInstallTaskTests : BaseTaskManagerTest - { - [Test] - public void GitInstallTest() - { - InitializeTaskManager(); - - var cacheContainer = Substitute.For(); - Environment = new IntegrationTestEnvironment(cacheContainer, TestBasePath, SolutionDirectory, enableTrace: true); - - var gitInstallationPath = TestBasePath.Combine("GitInstall").CreateDirectory(); - - var gitInstallDetails = new PortableGitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows); - var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails); - - gitInstallTask.Start().Wait(); - - Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath).Should().Be(PortableGitInstallDetails.ExtractedMD5); - Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath, false).Should().Be(PortableGitInstallDetails.FileListMD5); - - new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails) - .Then(new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails)) - .Start() - .Wait(); - } - } -} \ No newline at end of file diff --git a/src/tests/IntegrationTests/IntegrationTests.csproj b/src/tests/IntegrationTests/IntegrationTests.csproj index bf23c591f..8a8569652 100644 --- a/src/tests/IntegrationTests/IntegrationTests.csproj +++ b/src/tests/IntegrationTests/IntegrationTests.csproj @@ -81,7 +81,7 @@ - + From e672ac3186820039de3c4f1302ff067f220da0c8 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 3 Jan 2018 19:21:41 -0500 Subject: [PATCH 0050/1008] Integating download functionality --- src/GitHub.Api/Installer/GitInstaller.cs | 31 +++++++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 80fbb4b01..e540feec9 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -99,13 +99,36 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) else { var tempZipPath = NPath.CreateTempDirectory("git_zip_paths"); - var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", tempZipPath, environment); - var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", tempZipPath, environment); - + var gitArchivePath = tempZipPath.Combine("git.zip"); + var gitLfsArchivePath = tempZipPath.Combine("git-lfs.zip"); var gitExtractPath = tempZipPath.Combine("git").CreateDirectory(); var gitLfsExtractPath = tempZipPath.Combine("git-lfs").CreateDirectory(); - new UnzipTask(cancellationToken, gitArchivePath, gitExtractPath, sharpZipLibHelper) + var downloadGitMd5Task = new DownloadTextTask(CancellationToken.None, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt?cb=1"); + + var downloadGitTask = new DownloadTask(CancellationToken.None, environment.FileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip", gitArchivePath, retryCount: 1); + + var downloadGitLfsMd5Task = new DownloadTextTask(CancellationToken.None, + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt?cb=1"); + + var downloadGitLfsTask = new DownloadTask(CancellationToken.None, environment.FileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip", gitLfsArchivePath, retryCount: 1); + + downloadGitMd5Task + .Then((b, s) => + { + downloadGitTask.ValidationHash = s; + }) + .Then(downloadGitTask) + .Then(downloadGitLfsMd5Task) + .Then((b, s) => + { + downloadGitLfsTask.ValidationHash = s; + }) + .Then(downloadGitLfsTask) + .Then(new UnzipTask(cancellationToken, gitArchivePath, gitExtractPath, sharpZipLibHelper)) .Then(new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper)) .Then(() => { var targetGitLfsExecPath = installDetails.GetGitLfsExecPath(gitExtractPath); From 9c444b77903908821d6c4849afc7e820b16ace83 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 3 Jan 2018 19:33:27 -0500 Subject: [PATCH 0051/1008] Removing some unused code --- .../Application/ApplicationManagerBase.cs | 84 ------------------- .../BasePlatformIntegrationTest.cs | 10 +-- 2 files changed, 5 insertions(+), 89 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index fac8e4710..713dba131 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -110,90 +110,6 @@ public void Run(bool firstRun) }) ); } - private ITask SetupGit() - { - return BuildDetermineGitPathTask() - .Then((b, path) => { - Logger.Trace("Setting GitExecutablePath: {0}", path); - Environment.GitExecutablePath = path; - }) - .Then(() => { - if (Environment.GitExecutablePath == null) - { - if (Environment.IsWindows) - { - GitClient.GetConfig("credential.helper", GitConfigSource.Global).Then( - (b, credentialHelper) => { - if (!string.IsNullOrEmpty(credentialHelper)) - { - Logger.Trace("Windows CredentialHelper: {0}", credentialHelper); - } - else - { - Logger.Warning( - "No Windows CredentialHeloper found: Setting to wincred"); - - GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global).Start().Wait(); - } - }); - } - } - }) - .ThenInUI(() => { - Environment.User.Initialize(GitClient); - }); - } - - private TaskBase BuildDetermineGitPathTask() - { - TaskBase determinePath = new FuncTask(CancellationToken, () => { - if (Environment.GitExecutablePath != null) - { - return Environment.GitExecutablePath; - } - - var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath(); - if (gitExecutablePath != null && gitExecutablePath.FileExists()) - { - Logger.Trace("Using git install path from settings"); - return gitExecutablePath; - } - - return null; - }); - - var environmentIsWindows = Environment.IsWindows; - if (environmentIsWindows) - { - var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); - var installDetails = new GitInstallDetails(applicationDataPath, true); - var installTask = new PortableGitInstallTask(CancellationToken, Environment, installDetails); - - determinePath = determinePath.Then(new ShortCircuitTask(CancellationToken, installTask)); - } - - if (!environmentIsWindows) - { - determinePath = determinePath.Then(new ShortCircuitTask(CancellationToken, () => { - var p = new NPath("/usr/local/bin/git"); - - if (p.FileExists()) - { - return p; - } - - return null; - })); - - var findExecTask = new FindExecTask("git", CancellationToken); - findExecTask.Configure(ProcessManager); - - determinePath = determinePath.Then(new ShortCircuitTask(CancellationToken, findExecTask)); - } - - return determinePath; - } - public ITask InitializeRepository() { Logger.Trace("Running Repository Initialize"); diff --git a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs index 8a137ae6d..ba721d469 100644 --- a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs +++ b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs @@ -31,12 +31,12 @@ protected void InitializePlatform(NPath repoPath, NPath environmentPath, bool en { var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); var installDetails = new GitInstallDetails(applicationDataPath, true); - var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, installDetails); + //var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, installDetails); - var installPath = gitInstallTask.Start().Result; - Environment.GitExecutablePath = installPath; - - GitClient = new GitClient(Environment, ProcessManager, TaskManager.Token); + //var installPath = gitInstallTask.Start().Result; + //Environment.GitExecutablePath = installPath; + + //GitClient = new GitClient(Environment, ProcessManager, TaskManager.Token); } } } From 90965ea2165282e21e8ac98dab2c9577e27d996e Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 3 Jan 2018 19:43:47 -0500 Subject: [PATCH 0052/1008] Tweaking the md5 urls --- src/GitHub.Api/Installer/GitInstaller.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index e540feec9..b8f653848 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -105,13 +105,13 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) var gitLfsExtractPath = tempZipPath.Combine("git-lfs").CreateDirectory(); var downloadGitMd5Task = new DownloadTextTask(CancellationToken.None, - "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt?cb=1"); + "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt"); var downloadGitTask = new DownloadTask(CancellationToken.None, environment.FileSystem, "https://ghfvs-installer.github.com/unity/portable_git/git.zip", gitArchivePath, retryCount: 1); var downloadGitLfsMd5Task = new DownloadTextTask(CancellationToken.None, - "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt?cb=1"); + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt"); var downloadGitLfsTask = new DownloadTask(CancellationToken.None, environment.FileSystem, "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip", gitLfsArchivePath, retryCount: 1); From db6a62c608acdd7e2623e985502d2feb920eb915 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 3 Jan 2018 19:44:16 -0500 Subject: [PATCH 0053/1008] Removing some log messages --- src/GitHub.Api/Application/ApplicationManagerBase.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 713dba131..152c7f2b4 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -51,8 +51,6 @@ public void Run(bool firstRun) var afterGitSetup = new ActionTask(CancellationToken, RestartRepository) .ThenInUI(InitializeUI); - Logger.Trace("afterGitSetup"); - var windowsCredentialSetup = new ActionTask(CancellationToken, () => { GitClient.GetConfig("credential.helper", GitConfigSource.Global).Then((b, credentialHelper) => { if (!string.IsNullOrEmpty(credentialHelper)) @@ -70,8 +68,6 @@ public void Run(bool firstRun) }).Start(); }); - Logger.Trace("windowsCredentialSetup"); - var afterPathDetermined = new ActionTask(CancellationToken, (b1, path) => { Logger.Trace("Setting Environment git path: {0}", path); @@ -91,8 +87,6 @@ public void Run(bool firstRun) } }); - Logger.Trace("afterPathDetermined"); - var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); var installDetails = new GitInstallDetails(applicationDataPath, true); From a76e5f0769e92f773e43d901eec0011643464649 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 07:52:29 -0500 Subject: [PATCH 0054/1008] Removing ShortCircuitTask --- src/GitHub.Api/GitHub.Api.csproj | 1 - src/GitHub.Api/Installer/ShortCircuitTask.cs | 32 --------- .../Installer/ShortCircuitTaskTests.cs | 71 ------------------- .../IntegrationTests/IntegrationTests.csproj | 1 - 4 files changed, 105 deletions(-) delete mode 100644 src/GitHub.Api/Installer/ShortCircuitTask.cs delete mode 100644 src/tests/IntegrationTests/Installer/ShortCircuitTaskTests.cs diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 5eeb6655a..77c992810 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -118,7 +118,6 @@ - diff --git a/src/GitHub.Api/Installer/ShortCircuitTask.cs b/src/GitHub.Api/Installer/ShortCircuitTask.cs deleted file mode 100644 index 996d6eb19..000000000 --- a/src/GitHub.Api/Installer/ShortCircuitTask.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Threading; - -namespace GitHub.Unity -{ - class ShortCircuitTask : TaskBase where TResult : class - { - private readonly Func action; - - public ShortCircuitTask(CancellationToken token, TaskBase funcTask) : base(token) - { - action = () => funcTask.Start().Result; - } - - public ShortCircuitTask(CancellationToken token, Func action) : base(token) - { - this.action = action; - } - - protected override TResult RunWithData(bool success, TResult previousResult) - { - base.RunWithData(success, previousResult); - - if (success && previousResult != null) - { - return previousResult; - } - - return action(); - } - } -} \ No newline at end of file diff --git a/src/tests/IntegrationTests/Installer/ShortCircuitTaskTests.cs b/src/tests/IntegrationTests/Installer/ShortCircuitTaskTests.cs deleted file mode 100644 index 1d5a69842..000000000 --- a/src/tests/IntegrationTests/Installer/ShortCircuitTaskTests.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System.Threading; -using FluentAssertions; -using GitHub.Unity; -using NUnit.Framework; - -namespace IntegrationTests -{ - [TestFixture] - class ShortCircuitTaskTests : BaseTaskManagerTest - { - [Test] - public void ShouldSkipSecondTask() - { - InitializeTaskManager(); - Logger.Trace("ShouldSkipSecondTask"); - - var calledFirst = false; - var first = new FuncTask(CancellationToken.None, () => { - Logger.Trace("Returning First"); - calledFirst = true; - return "First"; - }); - - var calledSecond = false; - var second = new FuncTask(CancellationToken.None, () => { - Logger.Trace("Returning Second"); - calledSecond = true; - return "Second"; - }); - - var shortCircuitTask = new ShortCircuitTask(CancellationToken.None, second); - - var result = first - .Then(shortCircuitTask).Start().Result; - - result.Should().Be("First"); - calledFirst.Should().BeTrue(); - calledSecond.Should().BeFalse(); - } - - [Test] - public void ShouldRunSecondTask() - { - InitializeTaskManager(); - Logger.Trace("ShouldRunSecondTask"); - - var calledFirst = false; - var first = new FuncTask(CancellationToken.None, () => { - Logger.Trace("Returning First"); - calledFirst = true; - return null; - }); - - var calledSecond = false; - var second = new FuncTask(CancellationToken.None, () => { - Logger.Trace("Returning Second"); - calledSecond = true; - return "Second"; - }); - - var shortCircuitTask = new ShortCircuitTask(CancellationToken.None, second); - - var result = first - .Then(shortCircuitTask).Start().Result; - - result.Should().Be("Second"); - calledFirst.Should().BeTrue(); - calledSecond.Should().BeTrue(); - } - } -} \ No newline at end of file diff --git a/src/tests/IntegrationTests/IntegrationTests.csproj b/src/tests/IntegrationTests/IntegrationTests.csproj index 8a8569652..f2574a68b 100644 --- a/src/tests/IntegrationTests/IntegrationTests.csproj +++ b/src/tests/IntegrationTests/IntegrationTests.csproj @@ -82,7 +82,6 @@ - From 122abe08e9c151ea41ad1ea1afe64a461ef8d72d Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 07:53:43 -0500 Subject: [PATCH 0055/1008] Commenting out integration test output --- src/tests/IntegrationTests/SetUpFixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/IntegrationTests/SetUpFixture.cs b/src/tests/IntegrationTests/SetUpFixture.cs index 62793030c..21c14f375 100644 --- a/src/tests/IntegrationTests/SetUpFixture.cs +++ b/src/tests/IntegrationTests/SetUpFixture.cs @@ -14,7 +14,7 @@ public void Setup() Logging.LogAdapter = new MultipleLogAdapter( new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-integration-tests.log") - , new ConsoleLogAdapter() + //, new ConsoleLogAdapter() ); } } From 7ea50e5105232200280ca6b31f370cad8a6a15f1 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 08:00:58 -0500 Subject: [PATCH 0056/1008] Detecting errors properly when downloading --- src/GitHub.Api/Tasks/DownloadTask.cs | 7 ++++++- .../Download/DownloadTaskTests.cs | 21 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 2f5e7b59a..0d5bca859 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -85,7 +85,12 @@ public static WebResponse GetResponseWithoutException(this WebRequest request) } catch (WebException e) { - return e.Response; + if (e.Response != null) + { + return e.Response; + } + + throw e; } } } diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 3b5787580..8d233b69a 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -81,7 +81,6 @@ public void TestDownloadFailure() exceptionThrown.Should().NotBeNull(); } - [Test] public void TestDownloadTextTask() { @@ -92,6 +91,26 @@ public void TestDownloadTextTask() var resultLines = result.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); resultLines[0].Should().Be("# If you would like to crawl GitHub contact us at support@github.com."); } + + [Test] + public void TestDownloadTextFailture() + { + InitializeTaskManager(); + + var downloadTask = new DownloadTextTask(CancellationToken.None, "https://ggggithub.com/robots.txt"); + var exceptionThrown = false; + + try + { + var result = downloadTask.Start().Result; + } + catch (Exception e) + { + exceptionThrown = true; + } + + exceptionThrown.Should().BeTrue(); + } [Test] public void TestDownloadFileAndHash() From 693c67b6ca7c530d6db4c720afd5efe4102d54c4 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 08:07:36 -0500 Subject: [PATCH 0057/1008] Tweaking log messages --- src/GitHub.Api/Installer/UnzipTask.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/GitHub.Api/Installer/UnzipTask.cs b/src/GitHub.Api/Installer/UnzipTask.cs index 7478deb6f..ac832944b 100644 --- a/src/GitHub.Api/Installer/UnzipTask.cs +++ b/src/GitHub.Api/Installer/UnzipTask.cs @@ -38,12 +38,11 @@ protected override void Run(bool success) private void UnzipArchive() { - Logger.Trace("Zip File: {0}", archiveFilePath); - Logger.Trace("Target Path: {0}", extractedPath); + Logger.Trace("Unzip File: {0} to Path: {1}", archiveFilePath, extractedPath); zipHelper.Extract(archiveFilePath, extractedPath, Token, zipFileProgress, estimatedDurationProgress); - Logger.Trace("Completed"); + Logger.Trace("Completed Unzip"); } } } From d52f0f6347d32b4dd83dad68b55d77642fe34eea Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 08:12:20 -0500 Subject: [PATCH 0058/1008] Removing a bunch of redundant casts --- src/GitHub.Api/Installer/GitInstaller.cs | 2 +- src/tests/IntegrationTests/Git/GitSetupTests.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index b2d76dfc5..ad952bd09 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -96,7 +96,7 @@ public bool IsGitLfsExtracted() return false; } - var calculateMd5 = (string)environment.FileSystem.CalculateFileMD5((string)GitLfsExecutablePath); + var calculateMd5 = environment.FileSystem.CalculateFileMD5(GitLfsExecutablePath); logger.Trace("GitLFS MD5: {0}", calculateMd5); var md5 = environment.IsWindows ? WindowsGitLfsExecutableMD5 : MacGitLfsExecutableMD5; if (String.Compare(calculateMd5, md5, true) != 0) diff --git a/src/tests/IntegrationTests/Git/GitSetupTests.cs b/src/tests/IntegrationTests/Git/GitSetupTests.cs index 73651d020..f5b9fd520 100644 --- a/src/tests/IntegrationTests/Git/GitSetupTests.cs +++ b/src/tests/IntegrationTests/Git/GitSetupTests.cs @@ -41,7 +41,7 @@ public async Task InstallGit() gitLfsDestinationPath = gitLfsDestinationPath.Combine("libexec", "git-core", "git-lfs.exe"); gitLfsDestinationPath.FileExists().Should().BeTrue(); - var calculateMd5 = (string)NPath.FileSystem.CalculateFileMD5((string)gitLfsDestinationPath); + var calculateMd5 = NPath.FileSystem.CalculateFileMD5(gitLfsDestinationPath); Assert.IsTrue(string.Compare(calculateMd5, GitInstaller.WindowsGitLfsExecutableMD5, true) == 0); setupDone = await gitSetup.SetupIfNeeded(new Progress(x => percent = x)); @@ -83,7 +83,7 @@ public void VerifyWindowsGitLfsBundle() gitLfsPath.Exists().Should().BeTrue(); - var calculateMd5 = (string)NPath.FileSystem.CalculateFileMD5((string)gitLfsPath); + var calculateMd5 = NPath.FileSystem.CalculateFileMD5(gitLfsPath); calculateMd5.ToLower().Should().Be(GitInstaller.WindowsGitLfsExecutableMD5.ToLower()); } @@ -103,7 +103,7 @@ public void VerifyMacGitLfsBundle() gitLfsPath.Exists().Should().BeTrue(); - var calculateMd5 = (string)NPath.FileSystem.CalculateFileMD5((string)gitLfsPath); + var calculateMd5 = NPath.FileSystem.CalculateFileMD5(gitLfsPath); calculateMd5.ToLower().Should().Be(GitInstaller.MacGitLfsExecutableMD5.ToLower()); } } From 3cf8660d1b1c1fd29726a5551c3f3c6fd2ac5d73 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 08:14:43 -0500 Subject: [PATCH 0059/1008] Adding functionality to skip the contents of a file when generating an MD5 This gives us a much faster test for the existence of files and not their contents --- src/GitHub.Api/Extensions/FileSystemExtensions.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/Extensions/FileSystemExtensions.cs b/src/GitHub.Api/Extensions/FileSystemExtensions.cs index 4953cf96d..c0dda0829 100644 --- a/src/GitHub.Api/Extensions/FileSystemExtensions.cs +++ b/src/GitHub.Api/Extensions/FileSystemExtensions.cs @@ -22,7 +22,7 @@ public static string CalculateFileMD5(this IFileSystem fileSystem, string file) return BitConverter.ToString(computeHash).Replace("-", string.Empty).ToLower(); } - public static string CalculateFolderMD5(this IFileSystem fileSystem, string path) + public static string CalculateFolderMD5(this IFileSystem fileSystem, string path, bool includeContents = true) { //https://stackoverflow.com/questions/3625658/creating-hash-for-folder @@ -39,9 +39,12 @@ public static string CalculateFolderMD5(this IFileSystem fileSystem, string path var pathBytes = Encoding.UTF8.GetBytes(relativeFilePath); md5.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0); - // hash contents - var contentBytes = File.ReadAllBytes(filePath); - md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0); + if (includeContents) + { + // hash contents + var contentBytes = File.ReadAllBytes(filePath); + md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0); + } } //Handles empty filePaths case From 739584af61985fb9688bf9465df8d855b123c5db Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 08:56:54 -0500 Subject: [PATCH 0060/1008] Changing to full profile --- src/GitHub.Api/GitHub.Api.csproj | 2 +- src/GitHub.Logging/GitHub.Logging.csproj | 2 +- .../Assets/Editor/GitHub.Unity/GitHub.Unity.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 3b64122c5..b6c27a167 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -27,7 +27,7 @@ prompt 4 true - $(SolutionDir)\common\codeanalysis-small.ruleset + $(SolutionDir)\common\codeanalysis-full.ruleset false true diff --git a/src/GitHub.Logging/GitHub.Logging.csproj b/src/GitHub.Logging/GitHub.Logging.csproj index b4d9815e0..9fa335c43 100644 --- a/src/GitHub.Logging/GitHub.Logging.csproj +++ b/src/GitHub.Logging/GitHub.Logging.csproj @@ -22,7 +22,7 @@ prompt 4 true - $(SolutionDir)\common\codeanalysis-small.ruleset + $(SolutionDir)\common\codeanalysis-full.ruleset AnyCPU diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj index 71964b21e..701947bc4 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj @@ -23,7 +23,7 @@ prompt 4 true - $(SolutionDir)\common\codeanalysis-small.ruleset + $(SolutionDir)\common\codeanalysis-full.ruleset 4 From dc1bb42a2776d8ddd43c018c5427c05dd6ba29fb Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 09:04:00 -0500 Subject: [PATCH 0061/1008] Fixing some string comparisons --- src/GitHub.Api/IO/NiceIO.cs | 5 +++-- src/GitHub.Api/Installer/GitInstaller.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/GitHub.Api/IO/NiceIO.cs b/src/GitHub.Api/IO/NiceIO.cs index 0b10a5f0a..2fc09c508 100644 --- a/src/GitHub.Api/IO/NiceIO.cs +++ b/src/GitHub.Api/IO/NiceIO.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text; @@ -463,8 +464,8 @@ public int CompareTo(object obj) public bool HasExtension(params string[] extensions) { - var extensionWithDotLower = ExtensionWithDot.ToLower(); - return extensions.Any(e => WithDot(e).ToLower() == extensionWithDotLower); + var extensionWithDotLower = ExtensionWithDot.ToLower(CultureInfo.InvariantCulture); + return extensions.Any(e => WithDot(e).ToLower(CultureInfo.InvariantCulture) == extensionWithDotLower); } private static string WithDot(string extension) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index f54765298..ef7640fef 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -99,7 +99,7 @@ public bool IsGitLfsExtracted() var calculateMd5 = environment.FileSystem.CalculateMD5(GitLfsExecutablePath); logger.Trace("GitLFS MD5: {0}", calculateMd5); var md5 = environment.IsWindows ? WindowsGitLfsExecutableMD5 : MacGitLfsExecutableMD5; - if (String.Compare(calculateMd5, md5, true) != 0) + if (md5.Equals(calculateMd5, StringComparison.InvariantCultureIgnoreCase)) { logger.Trace("{0} has incorrect MD5", GitExecutablePath); return false; From e6280b62a12eeb9f4073c7f942efcc0390ebe374 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 09:08:50 -0500 Subject: [PATCH 0062/1008] Adding Serializable attribute to exception classes --- src/GitHub.Api/Application/ApiClient.cs | 3 +++ src/GitHub.Api/Helpers/Guard.cs | 1 + src/GitHub.Api/Helpers/TaskHelpers.cs | 1 + src/GitHub.Api/Tasks/TaskCanceledExceptions.cs | 2 ++ 4 files changed, 7 insertions(+) diff --git a/src/GitHub.Api/Application/ApiClient.cs b/src/GitHub.Api/Application/ApiClient.cs index d456e35af..a02db0bc4 100644 --- a/src/GitHub.Api/Application/ApiClient.cs +++ b/src/GitHub.Api/Application/ApiClient.cs @@ -332,6 +332,7 @@ class GitHubRepository public string CloneUrl { get; set; } } + [Serializable] class ApiClientException : Exception { public ApiClientException() @@ -344,6 +345,7 @@ public ApiClientException(string message, Exception innerException) : base(messa { } } + [Serializable] class TokenUsernameMismatchException : ApiClientException { public string CachedUsername { get; } @@ -356,6 +358,7 @@ public TokenUsernameMismatchException(string cachedUsername, string currentUsern } } + [Serializable] class KeychainEmptyException : ApiClientException { public KeychainEmptyException() diff --git a/src/GitHub.Api/Helpers/Guard.cs b/src/GitHub.Api/Helpers/Guard.cs index 2fe2e828e..ae75bfb50 100644 --- a/src/GitHub.Api/Helpers/Guard.cs +++ b/src/GitHub.Api/Helpers/Guard.cs @@ -5,6 +5,7 @@ namespace GitHub.Unity { + [Serializable] internal class InstanceNotInitializedException : InvalidOperationException { public InstanceNotInitializedException(object the, string property) : diff --git a/src/GitHub.Api/Helpers/TaskHelpers.cs b/src/GitHub.Api/Helpers/TaskHelpers.cs index 1698b92ab..eaaafd4fa 100644 --- a/src/GitHub.Api/Helpers/TaskHelpers.cs +++ b/src/GitHub.Api/Helpers/TaskHelpers.cs @@ -18,6 +18,7 @@ public static Task ToTask(this Exception exception) } } + [Serializable] public class NotReadyException : Exception { } diff --git a/src/GitHub.Api/Tasks/TaskCanceledExceptions.cs b/src/GitHub.Api/Tasks/TaskCanceledExceptions.cs index bdd8b96ed..cde037ce6 100644 --- a/src/GitHub.Api/Tasks/TaskCanceledExceptions.cs +++ b/src/GitHub.Api/Tasks/TaskCanceledExceptions.cs @@ -3,12 +3,14 @@ namespace GitHub.Unity { + [Serializable] class DependentTaskFailedException : TaskCanceledException { public DependentTaskFailedException(ITask task, Exception ex) : base(ex.InnerException != null ? ex.InnerException.Message : ex.Message, ex.InnerException ?? ex) {} } + [Serializable] class ProcessException : TaskCanceledException { public ProcessException(ITask process) : base(process.Errors) From 264141df23d24df00c81cdc2ac1b91a6eff9b0df Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 09:20:36 -0500 Subject: [PATCH 0063/1008] Using string.empty --- src/GitHub.Api/Helpers/AssemblyResources.cs | 2 +- src/GitHub.Api/IO/NiceIO.cs | 2 +- src/GitHub.Api/OutputProcessors/LogEntryOutputProcessor.cs | 2 +- .../Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs | 2 +- src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/GitHub.Api/Helpers/AssemblyResources.cs b/src/GitHub.Api/Helpers/AssemblyResources.cs index 28303eca8..06412e5b1 100644 --- a/src/GitHub.Api/Helpers/AssemblyResources.cs +++ b/src/GitHub.Api/Helpers/AssemblyResources.cs @@ -25,7 +25,7 @@ public static NPath ToFile(ResourceType resourceType, string resource, NPath des : resourceType == ResourceType.Platform ? "PlatformResources" : "Resources"; var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream( - String.Format("GitHub.Unity.{0}{1}.{2}", type, os != "" ? "." + os : os, resource)); + String.Format("GitHub.Unity.{0}{1}.{2}", type, !string.IsNullOrEmpty(os) ? "." + os : os, resource)); if (stream != null) return destinationPath.Combine(resource).WriteAllBytes(stream.ToByteArray()); diff --git a/src/GitHub.Api/IO/NiceIO.cs b/src/GitHub.Api/IO/NiceIO.cs index 0b10a5f0a..e4c466dd7 100644 --- a/src/GitHub.Api/IO/NiceIO.cs +++ b/src/GitHub.Api/IO/NiceIO.cs @@ -222,7 +222,7 @@ public NPath ChangeExtension(string extension) var newElements = (string[])_elements.Clone(); newElements[newElements.Length - 1] = FileSystem.ChangeExtension(_elements[_elements.Length - 1], WithDot(extension)); - if (extension == string.Empty) + if (string.IsNullOrEmpty(extension)) newElements[newElements.Length - 1] = newElements[newElements.Length - 1].TrimEnd('.'); return new NPath(newElements, _isRelative, _driveLetter); } diff --git a/src/GitHub.Api/OutputProcessors/LogEntryOutputProcessor.cs b/src/GitHub.Api/OutputProcessors/LogEntryOutputProcessor.cs index 4e916a62c..493f3760f 100644 --- a/src/GitHub.Api/OutputProcessors/LogEntryOutputProcessor.cs +++ b/src/GitHub.Api/OutputProcessors/LogEntryOutputProcessor.cs @@ -175,7 +175,7 @@ public override void LineReceived(string line) break; case ProcessingPhase.Files: - if (line == string.Empty) + if (string.IsNullOrEmpty(line)) { ReturnGitLogEntry(); return; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs index d75bc4171..32f5f7042 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs @@ -37,7 +37,7 @@ private NPath FilePath { if (nFilePath == null) { - if (filePath == "") + if (string.IsNullOrEmpty(filePath)) return null; if (filePath == null) filePath = GetFilePath(); diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs index 99ab79516..beb262b11 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs @@ -161,7 +161,7 @@ public override void OnGUI() var organization = owners[selectedOwner] == username ? null : owners[selectedOwner]; var cleanRepoDescription = repoDescription.Trim(); - cleanRepoDescription = cleanRepoDescription == string.Empty ? null : cleanRepoDescription; + cleanRepoDescription = string.IsNullOrEmpty(cleanRepoDescription) ? null : cleanRepoDescription; Client.CreateRepository(new NewRepository(repoName) { From 659f547a0e3733f69a17ab91dd6667365ad44232 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 09:28:11 -0500 Subject: [PATCH 0064/1008] Refactor RepositoryWatcher to use a HashSet and remove an unused object --- src/GitHub.Api/Events/RepositoryWatcher.cs | 52 ++++++++++------------ 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/src/GitHub.Api/Events/RepositoryWatcher.cs b/src/GitHub.Api/Events/RepositoryWatcher.cs index cf7b4379a..803537c79 100644 --- a/src/GitHub.Api/Events/RepositoryWatcher.cs +++ b/src/GitHub.Api/Events/RepositoryWatcher.cs @@ -149,7 +149,7 @@ public int CheckAndProcessEvents() private int ProcessEvents(Event[] fileEvents) { - Dictionary> events = new Dictionary>(); + var events = new HashSet(); foreach (var fileEvent in fileEvents) { if (!running) @@ -177,90 +177,90 @@ private int ProcessEvents(Event[] fileEvents) // handling events in .git/* if (fileA.IsChildOf(paths.DotGitPath)) { - if (!events.ContainsKey(EventType.ConfigChanged) && fileA.Equals(paths.DotGitConfig)) + if (!events.Contains(EventType.ConfigChanged) && fileA.Equals(paths.DotGitConfig)) { - events.Add(EventType.ConfigChanged, null); + events.Add(EventType.ConfigChanged); } - else if (!events.ContainsKey(EventType.HeadChanged) && fileA.Equals(paths.DotGitHead)) + else if (!events.Contains(EventType.HeadChanged) && fileA.Equals(paths.DotGitHead)) { - events.Add(EventType.HeadChanged, null); + events.Add(EventType.HeadChanged); } - else if (!events.ContainsKey(EventType.IndexChanged) && fileA.Equals(paths.DotGitIndex)) + else if (!events.Contains(EventType.IndexChanged) && fileA.Equals(paths.DotGitIndex)) { - events.Add(EventType.IndexChanged, null); + events.Add(EventType.IndexChanged); } - else if (!events.ContainsKey(EventType.RemoteBranchesChanged) && fileA.IsChildOf(paths.RemotesPath)) + else if (!events.Contains(EventType.RemoteBranchesChanged) && fileA.IsChildOf(paths.RemotesPath)) { - events.Add(EventType.RemoteBranchesChanged, null); + events.Add(EventType.RemoteBranchesChanged); } - else if (!events.ContainsKey(EventType.LocalBranchesChanged) && fileA.IsChildOf(paths.BranchesPath)) + else if (!events.Contains(EventType.LocalBranchesChanged) && fileA.IsChildOf(paths.BranchesPath)) { - events.Add(EventType.LocalBranchesChanged, null); + events.Add(EventType.LocalBranchesChanged); } - else if (!events.ContainsKey(EventType.RepositoryCommitted) && fileA.IsChildOf(paths.DotGitCommitEditMsg)) + else if (!events.Contains(EventType.RepositoryCommitted) && fileA.IsChildOf(paths.DotGitCommitEditMsg)) { - events.Add(EventType.RepositoryCommitted, null); + events.Add(EventType.RepositoryCommitted); } } else { - if (events.ContainsKey(EventType.RepositoryChanged) || ignoredPaths.Any(ignoredPath => fileA.IsChildOf(ignoredPath))) + if (events.Contains(EventType.RepositoryChanged) || ignoredPaths.Any(ignoredPath => fileA.IsChildOf(ignoredPath))) { continue; } - events.Add(EventType.RepositoryChanged, null); + events.Add(EventType.RepositoryChanged); } } return FireEvents(events); } - private int FireEvents(Dictionary> events) + private int FireEvents(HashSet events) { int eventsProcessed = 0; - if (events.ContainsKey(EventType.ConfigChanged)) + if (events.Contains(EventType.ConfigChanged)) { Logger.Trace("ConfigChanged"); ConfigChanged?.Invoke(); eventsProcessed++; } - if (events.ContainsKey(EventType.HeadChanged)) + if (events.Contains(EventType.HeadChanged)) { Logger.Trace("HeadChanged"); HeadChanged?.Invoke(); eventsProcessed++; } - if (events.ContainsKey(EventType.LocalBranchesChanged)) + if (events.Contains(EventType.LocalBranchesChanged)) { Logger.Trace("LocalBranchesChanged"); LocalBranchesChanged?.Invoke(); eventsProcessed++; } - if (events.ContainsKey(EventType.RemoteBranchesChanged)) + if (events.Contains(EventType.RemoteBranchesChanged)) { Logger.Trace("RemoteBranchesChanged"); RemoteBranchesChanged?.Invoke(); eventsProcessed++; } - if (events.ContainsKey(EventType.IndexChanged)) + if (events.Contains(EventType.IndexChanged)) { Logger.Trace("IndexChanged"); IndexChanged?.Invoke(); eventsProcessed++; } - if (events.ContainsKey(EventType.RepositoryChanged)) + if (events.Contains(EventType.RepositoryChanged)) { Logger.Trace("RepositoryChanged"); RepositoryChanged?.Invoke(); eventsProcessed++; } - if (events.ContainsKey(EventType.RepositoryCommitted)) + if (events.Contains(EventType.RepositoryCommitted)) { Logger.Trace("RepositoryCommitted"); RepositoryCommitted?.Invoke(); @@ -306,11 +306,5 @@ private enum EventType RepositoryChanged, RepositoryCommitted } - - private class EventData - { - public string Origin; - public string Branch; - } } } From 0ed478165d5ab16d3d56c1b91727a384b29ddc18 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 09:29:41 -0500 Subject: [PATCH 0065/1008] Removing other unused fields --- src/GitHub.Api/Git/RepositoryManager.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index 70edbe8cd..4f101b3d8 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -95,7 +95,6 @@ class RepositoryManager : IRepositoryManager { private readonly IGitConfig config; private readonly IGitClient gitClient; - private readonly IPlatform platform; private readonly IRepositoryPathConfiguration repositoryPaths; private readonly IRepositoryWatcher watcher; @@ -110,12 +109,11 @@ class RepositoryManager : IRepositoryManager public event Action> LocalBranchesUpdated; public event Action, Dictionary>> RemoteBranchesUpdated; - public RepositoryManager(IPlatform platform, IGitConfig gitConfig, + public RepositoryManager(IGitConfig gitConfig, IRepositoryWatcher repositoryWatcher, IGitClient gitClient, IRepositoryPathConfiguration repositoryPaths) { this.repositoryPaths = repositoryPaths; - this.platform = platform; this.gitClient = gitClient; this.watcher = repositoryWatcher; this.config = gitConfig; @@ -132,7 +130,7 @@ public static RepositoryManager CreateInstance(IPlatform platform, ITaskManager var repositoryWatcher = new RepositoryWatcher(platform, repositoryPathConfiguration, taskManager.Token); - return new RepositoryManager(platform, gitConfig, repositoryWatcher, + return new RepositoryManager(gitConfig, repositoryWatcher, gitClient, repositoryPathConfiguration); } From e6cdfaa20e3485b48f117d1215aa5ea632726521 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 13:47:03 -0500 Subject: [PATCH 0066/1008] Fixes needed after merge --- src/GitHub.Api/IO/IFileSystem.cs | 1 - src/GitHub.Api/Tasks/DownloadTask.cs | 2 +- src/tests/IntegrationTests/Download/DownloadTaskTests.cs | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/IO/IFileSystem.cs b/src/GitHub.Api/IO/IFileSystem.cs index 80afb8467..5955e623f 100644 --- a/src/GitHub.Api/IO/IFileSystem.cs +++ b/src/GitHub.Api/IO/IFileSystem.cs @@ -44,6 +44,5 @@ public interface IFileSystem char DirectorySeparatorChar { get; } bool ExistingPathIsDirectory(string path); void SetCurrentDirectory(string currentDirectory); - byte[] ReadAllBytes(string path); } } \ No newline at end of file diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 0d5bca859..b31ce5f09 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -130,7 +130,7 @@ protected override void Run(bool success) result = Download(); if (result && ValidationHash != null) { - var md5 = fileSystem.CalculateMD5(Destination); + var md5 = fileSystem.CalculateFileMD5(Destination); result = md5.Equals(ValidationHash, StringComparison.CurrentCultureIgnoreCase); if (!result) diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 8d233b69a..fd09ae497 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -31,7 +31,7 @@ public async Task TestDownloadTask() var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); Logger.Trace("File size {0} bytes", downloadPathBytes.Length); - var md5Sum = fileSystem.CalculateMD5(downloadPath); + var md5Sum = fileSystem.CalculateFileMD5(downloadPath); md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); var random = new Random(); @@ -48,7 +48,7 @@ public async Task TestDownloadTask() var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadHalfPath); Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); - md5Sum = fileSystem.CalculateMD5(downloadPath); + md5Sum = fileSystem.CalculateFileMD5(downloadPath); md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); } From d3bd89ede4c53f90cc632c2c5838acf6bf420e85 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 13:48:21 -0500 Subject: [PATCH 0067/1008] Code nit pick --- src/GitHub.Api/Application/ApplicationManagerBase.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 152c7f2b4..b1301254b 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -39,8 +39,7 @@ protected void Initialize() Logging.TracingEnabled = UserSettings.Get(Constants.TraceLoggingKey, false); ProcessManager = new ProcessManager(Environment, Platform.GitEnvironment, CancellationToken); Platform.Initialize(ProcessManager, TaskManager); - ITaskManager taskManager = TaskManager; - GitClient = new GitClient(Environment, ProcessManager, taskManager.Token); + GitClient = new GitClient(Environment, ProcessManager, TaskManager.Token); SetupMetrics(); } From c60df3046aae546a085f5c53c4a1eaa737174d9e Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 17:34:14 -0500 Subject: [PATCH 0068/1008] Fixing tests --- .../Application/ApplicationManagerBase.cs | 1 - .../BasePlatformIntegrationTest.cs | 34 ++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index b1301254b..50bf907c1 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -88,7 +88,6 @@ public void Run(bool firstRun) var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); var installDetails = new GitInstallDetails(applicationDataPath, true); - var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails); gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken, (b, s) => { diff --git a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs index ba721d469..7b1249112 100644 --- a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs +++ b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs @@ -1,8 +1,10 @@ +using System; using System.IO; using System.Threading; using System.Threading.Tasks; using GitHub.Unity; using NSubstitute; +using Octokit; namespace IntegrationTests { @@ -29,14 +31,38 @@ protected void InitializePlatform(NPath repoPath, NPath environmentPath, bool en if (setupGit) { + var autoResetEvent = new AutoResetEvent(false); + var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); var installDetails = new GitInstallDetails(applicationDataPath, true); - //var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, installDetails); + var gitInstaller = new GitInstaller(Environment, CancellationToken.None, installDetails); + + NPath result = null; + Exception ex = null; + + gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken.None, (b, path) => { + result = path; + autoResetEvent.Set(); + }), + new ActionTask(CancellationToken.None, (b, exception) => { + ex = exception; + autoResetEvent.Set(); + })); + + autoResetEvent.WaitOne(); + + if (result == null) + { + if (ex != null) + { + throw ex; + } - //var installPath = gitInstallTask.Start().Result; - //Environment.GitExecutablePath = installPath; + throw new Exception("Did not install git"); + } - //GitClient = new GitClient(Environment, ProcessManager, TaskManager.Token); + Environment.GitExecutablePath = result; + GitClient = new GitClient(Environment, ProcessManager, TaskManager.Token); } } } From 7e9647c7496cc6e34ebf8a4716c53b478c6bead3 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 17:35:30 -0500 Subject: [PATCH 0069/1008] Another test fix --- src/tests/IntegrationTests/Download/DownloadTaskTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index fd09ae497..dc37ce020 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -32,7 +32,7 @@ public async Task TestDownloadTask() Logger.Trace("File size {0} bytes", downloadPathBytes.Length); var md5Sum = fileSystem.CalculateFileMD5(downloadPath); - md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); + md5Sum.Should().Be(TestDownloadMD5); var random = new Random(); var takeCount = random.Next(downloadPathBytes.Length); @@ -49,7 +49,7 @@ public async Task TestDownloadTask() Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); md5Sum = fileSystem.CalculateFileMD5(downloadPath); - md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); + md5Sum.Should().Be(TestDownloadMD5); } [Test] From 2010d95aaf1f350b340ec62662c023f43792eba5 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 17:38:03 -0500 Subject: [PATCH 0070/1008] Fixing method for non-windows --- src/GitHub.Api/Installer/GitInstaller.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 80fbb4b01..4e35f7bdc 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -81,6 +81,7 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) if (!environment.IsWindows) { onFailure.Start(); + return; } new FuncTask(cancellationToken, IsGitExtracted) From 4351c31bbeba6f0a55c33a840fceec6d64b8203c Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 17:38:54 -0500 Subject: [PATCH 0071/1008] Adding comment --- 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 50bf907c1..1ead7970c 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -50,6 +50,7 @@ public void Run(bool firstRun) var afterGitSetup = new ActionTask(CancellationToken, RestartRepository) .ThenInUI(InitializeUI); + //GitClient.GetConfig cannot be called until there is a git path set so it is wrapped in an ActionTask var windowsCredentialSetup = new ActionTask(CancellationToken, () => { GitClient.GetConfig("credential.helper", GitConfigSource.Global).Then((b, credentialHelper) => { if (!string.IsNullOrEmpty(credentialHelper)) From ff3a3e8a1f78e74f2ad86af36d7ea2a9d0a2ff5c Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 4 Jan 2018 17:46:02 -0500 Subject: [PATCH 0072/1008] Finding the executable if it cannot be installed --- .../Application/ApplicationManagerBase.cs | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 1ead7970c..84e7baa38 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -68,7 +68,7 @@ public void Run(bool firstRun) }).Start(); }); - var afterPathDetermined = new ActionTask(CancellationToken, (b1, path) => { + var afterPathDetermined = new ActionTask(CancellationToken, (b, path) => { Logger.Trace("Setting Environment git path: {0}", path); Environment.GitExecutablePath = path; @@ -87,19 +87,38 @@ public void Run(bool firstRun) } }); + var findExecTask = new FindExecTask("git", CancellationToken) + .Finally((b, ex, path) => { + if (b && path != null) + { + Logger.Trace("FindExecTask Success: {0}", path); + + new FuncTask(CancellationToken, () => path) + .Then(afterPathDetermined) + .Start(); + } + else + { + Logger.Warning("FindExecTask Failure"); + Logger.Error("Git not found"); + } + }); + var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); var installDetails = new GitInstallDetails(applicationDataPath, true); var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails); - gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken, (b, s) => { + gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken, (b, path) => { - Logger.Trace("Success: {0}", s); + Logger.Trace("GitInstaller Success: {0}", path); - new FuncTask(CancellationToken, () => s) + new FuncTask(CancellationToken, () => path) .Then(afterPathDetermined) .Start(); }), new ActionTask(CancellationToken, () => { - Logger.Trace("Failure"); + Logger.Warning("GitInstaller Failure"); + + findExecTask.Start(); }) ); } From b96d20fa716a607ed4d2045c4f639400dbb263fc Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 08:58:05 -0500 Subject: [PATCH 0073/1008] Making sure the parent directory exists when copying portable git --- src/GitHub.Api/Installer/GitInstaller.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 4e35f7bdc..b2ddb5477 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -124,6 +124,7 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) Logger.Trace("Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", gitExtractPath, installDetails.GitInstallPath); + installDetails.GitInstallPath.EnsureParentDirectoryExists(); gitExtractPath.Move(installDetails.GitInstallPath); Logger.Trace("Deleting tempZipPath:\"{0}\"", tempZipPath); From e6762b5147c9365bec04b5a4754b0a3d25287584 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 09:00:13 -0500 Subject: [PATCH 0074/1008] Tweaking blank lines --- src/GitHub.Api/Application/ApplicationManagerBase.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 84e7baa38..052f55083 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -69,12 +69,9 @@ public void Run(bool firstRun) }); var afterPathDetermined = new ActionTask(CancellationToken, (b, path) => { - Logger.Trace("Setting Environment git path: {0}", path); Environment.GitExecutablePath = path; - }).ThenInUI(() => { - Environment.User.Initialize(GitClient); if (Environment.IsWindows) @@ -106,18 +103,15 @@ public void Run(bool firstRun) var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); var installDetails = new GitInstallDetails(applicationDataPath, true); + var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails); gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken, (b, path) => { - Logger.Trace("GitInstaller Success: {0}", path); - new FuncTask(CancellationToken, () => path) .Then(afterPathDetermined) .Start(); - }), new ActionTask(CancellationToken, () => { Logger.Warning("GitInstaller Failure"); - findExecTask.Start(); }) ); } From be45db5036462bdcd4672a92d8e37e79c800d30f Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 10:36:10 -0500 Subject: [PATCH 0075/1008] Adding functionality to check the MD5 of the git lfs exec --- src/GitHub.Api/Installer/GitInstaller.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index b2ddb5477..e87815fe8 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -11,6 +11,9 @@ class GitInstallDetails public string GitLfsExec { get; } public NPath GitLfsExecPath { get; } + public const string WindowsGitLfsExecutableMD5 = "177bb14d0c08f665a24f0d5516c3b080"; + public const string MacGitLfsExecutableMD5 = "f81a1a065a26a4123193e8fd96c561ad"; + public const string ExtractedMD5 = "65fd0575d3b47d8207b9e19d02faca4f"; public const string FileListMD5 = "a152a216b2e76f6c127053251187a278"; @@ -166,6 +169,14 @@ private bool IsGitExtracted() return false; } + var calculateMd5 = environment.FileSystem.CalculateFileMD5(installDetails.GitLfsExecPath); + var md5 = environment.IsWindows ? GitInstallDetails.WindowsGitLfsExecutableMD5 : GitInstallDetails.MacGitLfsExecutableMD5; + if (md5.Equals(calculateMd5, StringComparison.InvariantCultureIgnoreCase)) + { + Logger.Trace("{0} has MD5 {1} Excepted {2}", installDetails.GitLfsExecPath, calculateMd5, md5); + return false; + } + Logger.Trace("Git Present"); return true; } From 421a8764a0452cd214b8232ac45644b6fceaa51b Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 11:21:34 -0500 Subject: [PATCH 0076/1008] Adding functionality to UnzipTask to check the expected MD5 --- src/GitHub.Api/IO/IFileSystem.cs | 1 - src/GitHub.Api/Installer/UnzipTask.cs | 52 +++++++++++++++---- src/GitHub.Api/Tasks/DownloadTask.cs | 2 +- .../Download/DownloadTaskTests.cs | 4 +- src/tests/IntegrationTests/SetUpFixture.cs | 2 +- src/tests/IntegrationTests/UnzipTaskTests.cs | 44 ++++++++++++++-- 6 files changed, 84 insertions(+), 21 deletions(-) diff --git a/src/GitHub.Api/IO/IFileSystem.cs b/src/GitHub.Api/IO/IFileSystem.cs index 80afb8467..5955e623f 100644 --- a/src/GitHub.Api/IO/IFileSystem.cs +++ b/src/GitHub.Api/IO/IFileSystem.cs @@ -44,6 +44,5 @@ public interface IFileSystem char DirectorySeparatorChar { get; } bool ExistingPathIsDirectory(string path); void SetCurrentDirectory(string currentDirectory); - byte[] ReadAllBytes(string path); } } \ No newline at end of file diff --git a/src/GitHub.Api/Installer/UnzipTask.cs b/src/GitHub.Api/Installer/UnzipTask.cs index ac832944b..f12902eef 100644 --- a/src/GitHub.Api/Installer/UnzipTask.cs +++ b/src/GitHub.Api/Installer/UnzipTask.cs @@ -7,24 +7,27 @@ namespace GitHub.Unity class UnzipTask: TaskBase { private readonly string archiveFilePath; - private readonly string extractedPath; + private readonly NPath extractedPath; private readonly IZipHelper zipHelper; + private readonly IFileSystem fileSystem; + private readonly string expectedMD5; private readonly IProgress zipFileProgress; private readonly IProgress estimatedDurationProgress; - public UnzipTask(CancellationToken token, string archiveFilePath, string extractedPath, - IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) : - this(token, archiveFilePath, extractedPath, ZipHelper.Instance, zipFileProgress, estimatedDurationProgress) + public UnzipTask(CancellationToken token, string archiveFilePath, NPath extractedPath, IFileSystem fileSystem, string expectedMD5 = null, IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) : + this(token, archiveFilePath, extractedPath, ZipHelper.Instance, fileSystem, expectedMD5, zipFileProgress, estimatedDurationProgress) { } - public UnzipTask(CancellationToken token, string archiveFilePath, string extractedPath, IZipHelper zipHelper, IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) + public UnzipTask(CancellationToken token, string archiveFilePath, NPath extractedPath, IZipHelper zipHelper, IFileSystem fileSystem, string expectedMD5 = null, IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) : base(token) { this.archiveFilePath = archiveFilePath; this.extractedPath = extractedPath; this.zipHelper = zipHelper; + this.fileSystem = fileSystem; + this.expectedMD5 = expectedMD5; this.zipFileProgress = zipFileProgress; this.estimatedDurationProgress = estimatedDurationProgress; } @@ -33,16 +36,43 @@ protected override void Run(bool success) { base.Run(success); - UnzipArchive(); - } - - private void UnzipArchive() - { Logger.Trace("Unzip File: {0} to Path: {1}", archiveFilePath, extractedPath); - zipHelper.Extract(archiveFilePath, extractedPath, Token, zipFileProgress, estimatedDurationProgress); + try + { + zipHelper.Extract(archiveFilePath, extractedPath, Token, zipFileProgress, estimatedDurationProgress); + } + catch (Exception ex) + { + var message = "Error Unzipping file"; + + Logger.Error(ex, message); + throw new UnzipTaskException(message); + } + + if (expectedMD5 != null) + { + var calculatedMD5 = fileSystem.CalculateFolderMD5(extractedPath); + if (!calculatedMD5.Equals(expectedMD5, StringComparison.InvariantCultureIgnoreCase)) + { + extractedPath.DeleteIfExists(); + + var message = $"Extracted MD5: {calculatedMD5} Does not match expected: {expectedMD5}"; + Logger.Error(message); + + throw new UnzipTaskException(message); + } + } Logger.Trace("Completed Unzip"); } } + + public class UnzipTaskException : Exception { + public UnzipTaskException(string message) : base(message) + { } + + public UnzipTaskException(string message, Exception innerException) : base(message, innerException) + { } + } } diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 0d5bca859..b31ce5f09 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -130,7 +130,7 @@ protected override void Run(bool success) result = Download(); if (result && ValidationHash != null) { - var md5 = fileSystem.CalculateMD5(Destination); + var md5 = fileSystem.CalculateFileMD5(Destination); result = md5.Equals(ValidationHash, StringComparison.CurrentCultureIgnoreCase); if (!result) diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 8d233b69a..fd09ae497 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -31,7 +31,7 @@ public async Task TestDownloadTask() var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); Logger.Trace("File size {0} bytes", downloadPathBytes.Length); - var md5Sum = fileSystem.CalculateMD5(downloadPath); + var md5Sum = fileSystem.CalculateFileMD5(downloadPath); md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); var random = new Random(); @@ -48,7 +48,7 @@ public async Task TestDownloadTask() var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadHalfPath); Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); - md5Sum = fileSystem.CalculateMD5(downloadPath); + md5Sum = fileSystem.CalculateFileMD5(downloadPath); md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); } diff --git a/src/tests/IntegrationTests/SetUpFixture.cs b/src/tests/IntegrationTests/SetUpFixture.cs index 21c14f375..62793030c 100644 --- a/src/tests/IntegrationTests/SetUpFixture.cs +++ b/src/tests/IntegrationTests/SetUpFixture.cs @@ -14,7 +14,7 @@ public void Setup() Logging.LogAdapter = new MultipleLogAdapter( new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-integration-tests.log") - //, new ConsoleLogAdapter() + , new ConsoleLogAdapter() ); } } diff --git a/src/tests/IntegrationTests/UnzipTaskTests.cs b/src/tests/IntegrationTests/UnzipTaskTests.cs index e33677741..f3e13a540 100644 --- a/src/tests/IntegrationTests/UnzipTaskTests.cs +++ b/src/tests/IntegrationTests/UnzipTaskTests.cs @@ -1,5 +1,7 @@ +using System; using System.Threading; using System.Threading.Tasks; +using FluentAssertions; using GitHub.Unity; using Microsoft.Win32.SafeHandles; using NSubstitute; @@ -11,8 +13,10 @@ namespace IntegrationTests [TestFixture] class UnzipTaskTests : BaseTaskManagerTest { + private const string GitZipMD5 = "e6cfc0c294a2312042f27f893dfc9c0a"; + [Test] - public void UnzipTest() + public void TaskSucceeds() { InitializeTaskManager(); @@ -22,14 +26,11 @@ public void UnzipTest() var destinationPath = TestBasePath.Combine("git_zip").CreateDirectory(); var archiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", destinationPath, Environment); - Logger.Trace("ArchiveFilePath: {0}", archiveFilePath); - Logger.Trace("TestBasePath: {0}", TestBasePath); - var extractedPath = TestBasePath.Combine("git_zip_extracted").CreateDirectory(); var zipProgress = 0; Logger.Trace("Pct Complete {0}%", zipProgress); - var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, + var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, Environment.FileSystem, GitZipMD5, new Progress(zipFileProgress => { var zipFileProgressInteger = (int) (zipFileProgress * 100); if (zipProgress != zipFileProgressInteger) @@ -40,6 +41,39 @@ public void UnzipTest() })); unzipTask.Start().Wait(); + + extractedPath.DirectoryExists().Should().BeTrue(); + } + + [Test] + public void TaskFailsWhenMD5Incorect() + { + InitializeTaskManager(); + + var cacheContainer = Substitute.For(); + Environment = new IntegrationTestEnvironment(cacheContainer, TestBasePath, SolutionDirectory); + + var destinationPath = TestBasePath.Combine("git_zip").CreateDirectory(); + var archiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", destinationPath, Environment); + + var extractedPath = TestBasePath.Combine("git_zip_extracted").CreateDirectory(); + + + var failed = false; + Exception exception = null; + + var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, Environment.FileSystem, "AABBCCDD") + .Finally((b, ex) => { + failed = true; + exception = ex; + }); + + unzipTask.Start().Wait(); + + extractedPath.DirectoryExists().Should().BeFalse(); + failed.Should().BeTrue(); + exception.Should().NotBeNull(); + exception.Should().BeOfType(); } } } \ No newline at end of file From af0e24572a59973f45d09a93991aaf871ff5be14 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 11:59:45 -0500 Subject: [PATCH 0077/1008] Checking the hash of each zip --- src/GitHub.Api/Installer/GitInstaller.cs | 18 ++++++------------ src/tests/IntegrationTests/UnzipTaskTests.cs | 4 +--- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index e87815fe8..2ee91f014 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -11,10 +11,12 @@ class GitInstallDetails public string GitLfsExec { get; } public NPath GitLfsExecPath { get; } + public const string GitExtractedMD5 = "e6cfc0c294a2312042f27f893dfc9c0a"; + public const string GitLfsExtractedMD5 = "ae968b69fbf42dff72311040d24a"; + public const string WindowsGitLfsExecutableMD5 = "177bb14d0c08f665a24f0d5516c3b080"; public const string MacGitLfsExecutableMD5 = "f81a1a065a26a4123193e8fd96c561ad"; - public const string ExtractedMD5 = "65fd0575d3b47d8207b9e19d02faca4f"; public const string FileListMD5 = "a152a216b2e76f6c127053251187a278"; private const string PackageVersion = "f02737a78695063deace08e96d5042710d3e32db"; @@ -108,22 +110,14 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) var gitExtractPath = tempZipPath.Combine("git").CreateDirectory(); var gitLfsExtractPath = tempZipPath.Combine("git-lfs").CreateDirectory(); - - new UnzipTask(cancellationToken, gitArchivePath, gitExtractPath, sharpZipLibHelper) - .Then(new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper)) + + new UnzipTask(cancellationToken, gitArchivePath, gitExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitExtractedMD5) + .Then(new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5)) .Then(() => { var targetGitLfsExecPath = installDetails.GetGitLfsExecPath(gitExtractPath); var extractGitLfsExePath = gitLfsExtractPath.Combine(installDetails.GitLfsExec); extractGitLfsExePath.Move(targetGitLfsExecPath); - var extractedMD5 = environment.FileSystem.CalculateFolderMD5(gitExtractPath); - if (!extractedMD5.Equals(GitInstallDetails.ExtractedMD5, StringComparison.InvariantCultureIgnoreCase)) - { - Logger.Warning("MD5 {0} does not match expected {1}", extractedMD5, GitInstallDetails.ExtractedMD5); - Logger.Warning("Failed PortableGitInstallTask"); - throw new Exception(); - } - Logger.Trace("Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", gitExtractPath, installDetails.GitInstallPath); diff --git a/src/tests/IntegrationTests/UnzipTaskTests.cs b/src/tests/IntegrationTests/UnzipTaskTests.cs index f3e13a540..294159ba2 100644 --- a/src/tests/IntegrationTests/UnzipTaskTests.cs +++ b/src/tests/IntegrationTests/UnzipTaskTests.cs @@ -13,8 +13,6 @@ namespace IntegrationTests [TestFixture] class UnzipTaskTests : BaseTaskManagerTest { - private const string GitZipMD5 = "e6cfc0c294a2312042f27f893dfc9c0a"; - [Test] public void TaskSucceeds() { @@ -30,7 +28,7 @@ public void TaskSucceeds() var zipProgress = 0; Logger.Trace("Pct Complete {0}%", zipProgress); - var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, Environment.FileSystem, GitZipMD5, + var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, Environment.FileSystem, GitInstallDetails.GitExtractedMD5, new Progress(zipFileProgress => { var zipFileProgressInteger = (int) (zipFileProgress * 100); if (zipProgress != zipFileProgressInteger) From 6cf80036f96c2c5661391925db8528e2cf1cc743 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 15:15:27 -0500 Subject: [PATCH 0078/1008] Fixing tests and adding functionality to optionally download files --- src/GitHub.Api/Installer/GitInstaller.cs | 118 +++++++++++------- .../BasePlatformIntegrationTest.cs | 2 +- .../Installer/GitInstallerTests.cs | 47 +++++-- 3 files changed, 106 insertions(+), 61 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index f576dd0dc..af010913c 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -12,7 +12,7 @@ class GitInstallDetails public NPath GitLfsExecPath { get; } public const string GitExtractedMD5 = "e6cfc0c294a2312042f27f893dfc9c0a"; - public const string GitLfsExtractedMD5 = "ae968b69fbf42dff72311040d24a"; + public const string GitLfsExtractedMD5 = "36e3ae968b69fbf42dff72311040d24a"; public const string WindowsGitLfsExecutableMD5 = "177bb14d0c08f665a24f0d5516c3b080"; public const string MacGitLfsExecutableMD5 = "f81a1a065a26a4123193e8fd96c561ad"; @@ -65,18 +65,27 @@ class GitInstaller private readonly IZipHelper sharpZipLibHelper; private readonly CancellationToken cancellationToken; private readonly GitInstallDetails installDetails; + private NPath gitArchiveFilePath; + private NPath gitLfsArchivePath; public GitInstaller(IEnvironment environment, CancellationToken cancellationToken, GitInstallDetails installDetails) - : this(environment, ZipHelper.Instance, cancellationToken, installDetails) + : this(environment, ZipHelper.Instance, cancellationToken, installDetails, null, null) { } - public GitInstaller(IEnvironment environment, IZipHelper sharpZipLibHelper, CancellationToken cancellationToken, GitInstallDetails installDetails) + public GitInstaller(IEnvironment environment, CancellationToken cancellationToken, GitInstallDetails installDetails, NPath gitArchiveFilePath, NPath gitLfsArchivePath) + : this(environment, ZipHelper.Instance, cancellationToken, installDetails, gitArchiveFilePath, gitLfsArchivePath) + { + } + + public GitInstaller(IEnvironment environment, IZipHelper sharpZipLibHelper, CancellationToken cancellationToken, GitInstallDetails installDetails, NPath gitArchiveFilePath, NPath gitLfsArchivePath) { this.environment = environment; this.sharpZipLibHelper = sharpZipLibHelper; this.cancellationToken = cancellationToken; this.installDetails = installDetails; + this.gitArchiveFilePath = gitArchiveFilePath; + this.gitLfsArchivePath = gitLfsArchivePath; } public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) @@ -90,8 +99,7 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) } new FuncTask(cancellationToken, IsGitExtracted) - .Then((success, isPortableGitExtracted) => { - + .Finally((success, ex, isPortableGitExtracted) => { Logger.Trace("IsPortableGitExtracted: {0}", isPortableGitExtracted); if (isPortableGitExtracted) @@ -104,53 +112,33 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) } else { - var tempZipPath = NPath.CreateTempDirectory("git_zip_paths"); - var gitArchivePath = tempZipPath.Combine("git.zip"); - var gitLfsArchivePath = tempZipPath.Combine("git-lfs.zip"); - var gitExtractPath = tempZipPath.Combine("git").CreateDirectory(); - var gitLfsExtractPath = tempZipPath.Combine("git-lfs").CreateDirectory(); - - var downloadGitMd5Task = new DownloadTextTask(CancellationToken.None, - "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt"); - - var downloadGitTask = new DownloadTask(CancellationToken.None, environment.FileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git.zip", gitArchivePath, retryCount: 1); - - var downloadGitLfsMd5Task = new DownloadTextTask(CancellationToken.None, - "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt"); - - var downloadGitLfsTask = new DownloadTask(CancellationToken.None, environment.FileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip", gitLfsArchivePath, retryCount: 1); - - downloadGitMd5Task - .Then((b, s) => - { - downloadGitTask.ValidationHash = s; - }) - .Then(downloadGitTask) - .Then(downloadGitLfsMd5Task) - .Then((b, s) => - { - downloadGitLfsTask.ValidationHash = s; - }) - .Then(downloadGitLfsTask) - .Then(new UnzipTask(cancellationToken, gitArchivePath, gitExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitExtractedMD5)) - .Then(new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5)) + ITask downloadFilesTask1 = null; + if (gitArchiveFilePath == null || gitLfsArchivePath == null) + { + downloadFilesTask1 = CreateDownloadTask(); + } + + var tempZipExtractPath1 = NPath.CreateTempDirectory("git_zip_extract_zip_paths"); + var gitExtractPath1 = tempZipExtractPath1.Combine("git").CreateDirectory(); + var gitLfsExtractPath1 = tempZipExtractPath1.Combine("git-lfs").CreateDirectory(); + + var resultTask1 = new UnzipTask(cancellationToken, gitArchiveFilePath, gitExtractPath1, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitExtractedMD5) + .Then(new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath1, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5)) .Then(() => { - var targetGitLfsExecPath = installDetails.GetGitLfsExecPath(gitExtractPath); - var extractGitLfsExePath = gitLfsExtractPath.Combine(installDetails.GitLfsExec); - extractGitLfsExePath.Move(targetGitLfsExecPath); + var targetGitLfsExecPath1 = installDetails.GetGitLfsExecPath(gitExtractPath1); + var extractGitLfsExePath1 = gitLfsExtractPath1.Combine(installDetails.GitLfsExec); + extractGitLfsExePath1.Move(targetGitLfsExecPath1); - Logger.Trace("Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", gitExtractPath, + Logger.Trace("Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", gitExtractPath1, installDetails.GitInstallPath); installDetails.GitInstallPath.EnsureParentDirectoryExists(); - gitExtractPath.Move(installDetails.GitInstallPath); - - Logger.Trace("Deleting tempZipPath:\"{0}\"", tempZipPath); - tempZipPath.DeleteIfExists(); + gitExtractPath1.Move(installDetails.GitInstallPath); - }).Finally((b, exception) => { + Logger.Trace("Deleting tempZipPath:\"{0}\"", tempZipExtractPath1); + tempZipExtractPath1.DeleteIfExists(); + }) + .Finally((b, exception) => { if (b) { Logger.Trace("SetupGitIfNeeded: Success"); @@ -165,12 +153,48 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) onFailure.Start(); } - }).Start(); + }); + + if (downloadFilesTask1 != null) + { + resultTask1 = downloadFilesTask1.Then(resultTask1); + } + + resultTask1.Start(); } }).Start(); } + private ITask CreateDownloadTask() + { + var tempZipPath = NPath.CreateTempDirectory("git_zip_paths"); + gitArchiveFilePath = tempZipPath.Combine("git.zip"); + gitLfsArchivePath = tempZipPath.Combine("git-lfs.zip"); + + var downloadGitMd5Task = new DownloadTextTask(CancellationToken.None, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt"); + + var downloadGitTask = new DownloadTask(CancellationToken.None, environment.FileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip", gitArchiveFilePath, retryCount: 1); + + var downloadGitLfsMd5Task = new DownloadTextTask(CancellationToken.None, + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt"); + + var downloadGitLfsTask = new DownloadTask(CancellationToken.None, environment.FileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip", gitLfsArchivePath, retryCount: 1); + + return downloadGitMd5Task.Then((b, s) => { + downloadGitTask.ValidationHash = s; + }) + .Then(downloadGitTask) + .Then(downloadGitLfsMd5Task) + .Then((b, s) => { + downloadGitLfsTask.ValidationHash = s; + }) + .Then(downloadGitLfsTask); + } + private bool IsGitExtracted() { if (!installDetails.GitInstallPath.DirectoryExists()) diff --git a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs index 35685a177..e23264148 100644 --- a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs +++ b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs @@ -40,7 +40,7 @@ protected void InitializePlatform(NPath repoPath, NPath environmentPath, bool en var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); - var gitInstaller = new GitInstaller(Environment, CancellationToken.None, installDetails); + var gitInstaller = new GitInstaller(Environment, CancellationToken.None, installDetails, gitArchivePath, gitLfsArchivePath); NPath result = null; Exception ex = null; diff --git a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs index 870094948..e1a8f0fb0 100644 --- a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs +++ b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs @@ -1,5 +1,5 @@ +using System; using System.Threading; -using FluentAssertions; using GitHub.Unity; using NSubstitute; using NUnit.Framework; @@ -19,18 +19,39 @@ public void GitInstallTest() var gitInstallationPath = TestBasePath.Combine("GitInstall").CreateDirectory(); - var gitInstallDetails = new GitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows); -// var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails); -// -// gitInstallTask.Start().Wait(); -// -// Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath).Should().Be(PortableGitInstallDetails.ExtractedMD5); -// Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath, false).Should().Be(PortableGitInstallDetails.FileListMD5); -// -// new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails) -// .Then(new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails)) -// .Start() -// .Wait(); + var installDetails = new GitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows); + + var zipArchivesPath = TestBasePath.Combine("ZipArchives").CreateDirectory(); + var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); + var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); + + var gitInstaller = new GitInstaller(Environment, CancellationToken.None, installDetails, gitArchivePath, gitLfsArchivePath); + + var autoResetEvent = new AutoResetEvent(false); + + NPath result = null; + Exception ex = null; + + gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken.None, (b, path) => { + result = path; + autoResetEvent.Set(); + }), + new ActionTask(CancellationToken.None, (b, exception) => { + ex = exception; + autoResetEvent.Set(); + })); + + autoResetEvent.WaitOne(); + + if (result == null) + { + if (ex != null) + { + throw ex; + } + + throw new Exception("Did not install git"); + } } } } \ No newline at end of file From ab5af347e21a9732ecb6ab4f4d69bd3287211a98 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 15:35:49 -0500 Subject: [PATCH 0079/1008] Renaming variables --- src/GitHub.Api/Installer/GitInstaller.cs | 38 +++++++++++++----------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index af010913c..861f15622 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -112,31 +112,35 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) } else { - ITask downloadFilesTask1 = null; + ITask downloadFilesTask = null; if (gitArchiveFilePath == null || gitLfsArchivePath == null) { - downloadFilesTask1 = CreateDownloadTask(); + downloadFilesTask = CreateDownloadTask(); } - var tempZipExtractPath1 = NPath.CreateTempDirectory("git_zip_extract_zip_paths"); - var gitExtractPath1 = tempZipExtractPath1.Combine("git").CreateDirectory(); - var gitLfsExtractPath1 = tempZipExtractPath1.Combine("git-lfs").CreateDirectory(); + var tempZipExtractPath = NPath.CreateTempDirectory("git_zip_extract_zip_paths"); + var gitExtractPath = tempZipExtractPath.Combine("git").CreateDirectory(); + var gitLfsExtractPath = tempZipExtractPath.Combine("git-lfs").CreateDirectory(); - var resultTask1 = new UnzipTask(cancellationToken, gitArchiveFilePath, gitExtractPath1, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitExtractedMD5) - .Then(new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath1, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5)) + var resultTask = new UnzipTask(cancellationToken, gitArchiveFilePath, gitExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitExtractedMD5) + .Then(new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5)) .Then(() => { - var targetGitLfsExecPath1 = installDetails.GetGitLfsExecPath(gitExtractPath1); - var extractGitLfsExePath1 = gitLfsExtractPath1.Combine(installDetails.GitLfsExec); - extractGitLfsExePath1.Move(targetGitLfsExecPath1); + var targetGitLfsExecPath = installDetails.GetGitLfsExecPath(gitExtractPath); + var extractGitLfsExePath = gitLfsExtractPath.Combine(installDetails.GitLfsExec); - Logger.Trace("Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", gitExtractPath1, + Logger.Trace("Moving Git LFS Exe:\"{0}\" to target in tempDirectory:\"{1}\" ", extractGitLfsExePath, + targetGitLfsExecPath); + + extractGitLfsExePath.Move(targetGitLfsExecPath); + + Logger.Trace("Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", gitExtractPath, installDetails.GitInstallPath); installDetails.GitInstallPath.EnsureParentDirectoryExists(); - gitExtractPath1.Move(installDetails.GitInstallPath); + gitExtractPath.Move(installDetails.GitInstallPath); - Logger.Trace("Deleting tempZipPath:\"{0}\"", tempZipExtractPath1); - tempZipExtractPath1.DeleteIfExists(); + Logger.Trace("Deleting tempZipPath:\"{0}\"", tempZipExtractPath); + tempZipExtractPath.DeleteIfExists(); }) .Finally((b, exception) => { if (b) @@ -155,12 +159,12 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) } }); - if (downloadFilesTask1 != null) + if (downloadFilesTask != null) { - resultTask1 = downloadFilesTask1.Then(resultTask1); + resultTask = downloadFilesTask.Then(resultTask); } - resultTask1.Start(); + resultTask.Start(); } }).Start(); From 9426ca42674bf8400c5ef467d900ec7d649cdb32 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 15:35:59 -0500 Subject: [PATCH 0080/1008] Fixing tests --- .../Installer/GitInstallerTests.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs index e1a8f0fb0..87b9fd752 100644 --- a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs +++ b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs @@ -1,5 +1,6 @@ using System; using System.Threading; +using FluentAssertions; using GitHub.Unity; using NSubstitute; using NUnit.Framework; @@ -22,36 +23,35 @@ public void GitInstallTest() var installDetails = new GitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows); var zipArchivesPath = TestBasePath.Combine("ZipArchives").CreateDirectory(); + var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); - + var gitInstaller = new GitInstaller(Environment, CancellationToken.None, installDetails, gitArchivePath, gitLfsArchivePath); var autoResetEvent = new AutoResetEvent(false); - NPath result = null; + bool? result = null; + NPath resultPath = null; Exception ex = null; gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken.None, (b, path) => { - result = path; + result = true; + resultPath = path; autoResetEvent.Set(); }), new ActionTask(CancellationToken.None, (b, exception) => { + result = false; ex = exception; autoResetEvent.Set(); })); autoResetEvent.WaitOne(); - if (result == null) - { - if (ex != null) - { - throw ex; - } - - throw new Exception("Did not install git"); - } + result.HasValue.Should().BeTrue(); + result.Value.Should().BeTrue(); + resultPath.Should().NotBeNull(); + ex.Should().BeNull(); } } } \ No newline at end of file From 67893ea07919f21b6cef2ce27a438c451e6e68eb Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 15:36:39 -0500 Subject: [PATCH 0081/1008] Fixing logic statement --- src/GitHub.Api/Installer/GitInstaller.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 2ee91f014..0f03d3f1b 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -165,9 +165,9 @@ private bool IsGitExtracted() var calculateMd5 = environment.FileSystem.CalculateFileMD5(installDetails.GitLfsExecPath); var md5 = environment.IsWindows ? GitInstallDetails.WindowsGitLfsExecutableMD5 : GitInstallDetails.MacGitLfsExecutableMD5; - if (md5.Equals(calculateMd5, StringComparison.InvariantCultureIgnoreCase)) + if (!md5.Equals(calculateMd5, StringComparison.InvariantCultureIgnoreCase)) { - Logger.Trace("{0} has MD5 {1} Excepted {2}", installDetails.GitLfsExecPath, calculateMd5, md5); + Logger.Trace("{0} has MD5 {1} expected {2}", installDetails.GitLfsExecPath, calculateMd5, md5); return false; } From 38cf7b472bdea76f2d417b5af7f005bcc2df5dd4 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 15:39:54 -0500 Subject: [PATCH 0082/1008] Tweaking logs --- src/GitHub.Api/Installer/GitInstaller.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 0f03d3f1b..9089d8b97 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -152,14 +152,14 @@ private bool IsGitExtracted() { if (!installDetails.GitInstallPath.DirectoryExists()) { - Logger.Trace("{0} does not exist", installDetails.GitInstallPath); + Logger.Warning("{0} does not exist", installDetails.GitInstallPath); return false; } var fileListMD5 = environment.FileSystem.CalculateFolderMD5(installDetails.GitInstallPath, false); if (!fileListMD5.Equals(GitInstallDetails.FileListMD5, StringComparison.InvariantCultureIgnoreCase)) { - Logger.Trace("MD5 {0} does not match expected {1}", fileListMD5, GitInstallDetails.FileListMD5); + Logger.Warning("Path {0} has MD5 {1} expected {2}", installDetails.GitInstallPath, fileListMD5, GitInstallDetails.FileListMD5); return false; } @@ -167,7 +167,7 @@ private bool IsGitExtracted() var md5 = environment.IsWindows ? GitInstallDetails.WindowsGitLfsExecutableMD5 : GitInstallDetails.MacGitLfsExecutableMD5; if (!md5.Equals(calculateMd5, StringComparison.InvariantCultureIgnoreCase)) { - Logger.Trace("{0} has MD5 {1} expected {2}", installDetails.GitLfsExecPath, calculateMd5, md5); + Logger.Warning("Path {0} has MD5 {1} expected {2}", installDetails.GitLfsExecPath, calculateMd5, md5); return false; } From 020c6fc8bb3404be0eb492e3848b54798f176384 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 15:47:11 -0500 Subject: [PATCH 0083/1008] Correcting hash --- src/GitHub.Api/Installer/GitInstaller.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 9089d8b97..b25ef3b39 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -12,7 +12,7 @@ class GitInstallDetails public NPath GitLfsExecPath { get; } public const string GitExtractedMD5 = "e6cfc0c294a2312042f27f893dfc9c0a"; - public const string GitLfsExtractedMD5 = "ae968b69fbf42dff72311040d24a"; + public const string GitLfsExtractedMD5 = "36e3ae968b69fbf42dff72311040d24a"; public const string WindowsGitLfsExecutableMD5 = "177bb14d0c08f665a24f0d5516c3b080"; public const string MacGitLfsExecutableMD5 = "f81a1a065a26a4123193e8fd96c561ad"; From 443877932d06310c045af28a42629c69c0d14eac Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 16:11:04 -0500 Subject: [PATCH 0084/1008] Commenting out test output --- src/tests/IntegrationTests/SetUpFixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/IntegrationTests/SetUpFixture.cs b/src/tests/IntegrationTests/SetUpFixture.cs index 62793030c..21c14f375 100644 --- a/src/tests/IntegrationTests/SetUpFixture.cs +++ b/src/tests/IntegrationTests/SetUpFixture.cs @@ -14,7 +14,7 @@ public void Setup() Logging.LogAdapter = new MultipleLogAdapter( new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-integration-tests.log") - , new ConsoleLogAdapter() + //, new ConsoleLogAdapter() ); } } From 91cdd74f8a78057c4e3fef093f23881e6ce855a3 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 16:22:51 -0500 Subject: [PATCH 0085/1008] More tweaks --- src/GitHub.Api/Installer/GitInstaller.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index b25ef3b39..c3762e28d 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -124,6 +124,9 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) installDetails.GitInstallPath.EnsureParentDirectoryExists(); gitExtractPath.Move(installDetails.GitInstallPath); + Logger.Trace("Deleting targetGitLfsExecPath:\"{0}\"", targetGitLfsExecPath); + targetGitLfsExecPath.DeleteIfExists(); + Logger.Trace("Deleting tempZipPath:\"{0}\"", tempZipPath); tempZipPath.DeleteIfExists(); @@ -138,13 +141,12 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) } else { - Logger.Trace("SetupGitIfNeeded: Failed"); + Logger.Warning("SetupGitIfNeeded: Failed"); onFailure.Start(); } }).Start(); } - }).Start(); } From d58984ee589e555c92c30ee4fee5fbc4012c5b3b Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 16:28:19 -0500 Subject: [PATCH 0086/1008] Fixing build and unit test --- src/GitHub.Api/IO/IFileSystem.cs | 1 - src/GitHub.Api/Tasks/DownloadTask.cs | 2 +- src/tests/IntegrationTests/Download/DownloadTaskTests.cs | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/IO/IFileSystem.cs b/src/GitHub.Api/IO/IFileSystem.cs index 80afb8467..5955e623f 100644 --- a/src/GitHub.Api/IO/IFileSystem.cs +++ b/src/GitHub.Api/IO/IFileSystem.cs @@ -44,6 +44,5 @@ public interface IFileSystem char DirectorySeparatorChar { get; } bool ExistingPathIsDirectory(string path); void SetCurrentDirectory(string currentDirectory); - byte[] ReadAllBytes(string path); } } \ No newline at end of file diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 0d5bca859..b31ce5f09 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -130,7 +130,7 @@ protected override void Run(bool success) result = Download(); if (result && ValidationHash != null) { - var md5 = fileSystem.CalculateMD5(Destination); + var md5 = fileSystem.CalculateFileMD5(Destination); result = md5.Equals(ValidationHash, StringComparison.CurrentCultureIgnoreCase); if (!result) diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 8d233b69a..fd09ae497 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -31,7 +31,7 @@ public async Task TestDownloadTask() var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); Logger.Trace("File size {0} bytes", downloadPathBytes.Length); - var md5Sum = fileSystem.CalculateMD5(downloadPath); + var md5Sum = fileSystem.CalculateFileMD5(downloadPath); md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); var random = new Random(); @@ -48,7 +48,7 @@ public async Task TestDownloadTask() var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadHalfPath); Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); - md5Sum = fileSystem.CalculateMD5(downloadPath); + md5Sum = fileSystem.CalculateFileMD5(downloadPath); md5Sum.Should().Be(TestDownloadMD5.ToUpperInvariant()); } From db6d33a991ee3ff3355b2d37ff43f6bb9af52147 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 5 Jan 2018 17:08:28 -0500 Subject: [PATCH 0087/1008] Fixing test --- .../Installer/GitInstallerTests.cs | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs index 870094948..c2c6548c3 100644 --- a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs +++ b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs @@ -1,3 +1,4 @@ +using System; using System.Threading; using FluentAssertions; using GitHub.Unity; @@ -19,18 +20,33 @@ public void GitInstallTest() var gitInstallationPath = TestBasePath.Combine("GitInstall").CreateDirectory(); - var gitInstallDetails = new GitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows); -// var gitInstallTask = new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails); -// -// gitInstallTask.Start().Wait(); -// -// Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath).Should().Be(PortableGitInstallDetails.ExtractedMD5); -// Environment.FileSystem.CalculateFolderMD5(gitInstallDetails.GitInstallPath, false).Should().Be(PortableGitInstallDetails.FileListMD5); -// -// new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails) -// .Then(new PortableGitInstallTask(CancellationToken.None, Environment, gitInstallDetails)) -// .Start() -// .Wait(); + var installDetails = new GitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows); + + var gitInstaller = new GitInstaller(Environment, CancellationToken.None, installDetails); + + var autoResetEvent = new AutoResetEvent(false); + + bool? result = null; + NPath resultPath = null; + Exception ex = null; + + gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken.None, (b, path) => { + result = true; + resultPath = path; + autoResetEvent.Set(); + }), + new ActionTask(CancellationToken.None, (b, exception) => { + result = false; + ex = exception; + autoResetEvent.Set(); + })); + + autoResetEvent.WaitOne(); + + result.HasValue.Should().BeTrue(); + result.Value.Should().BeTrue(); + resultPath.Should().NotBeNull(); + ex.Should().BeNull(); } } } \ No newline at end of file From 2220d771d75f548c2c9a50afbad4374af3bbba5b Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 8 Jan 2018 13:25:44 -0500 Subject: [PATCH 0088/1008] Checking user settings before finding or installing git --- .../Application/ApplicationManagerBase.cs | 67 ++++++++++++------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 052f55083..73b73f536 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -84,36 +84,51 @@ public void Run(bool firstRun) } }); - var findExecTask = new FindExecTask("git", CancellationToken) - .Finally((b, ex, path) => { - if (b && path != null) - { - Logger.Trace("FindExecTask Success: {0}", path); - - new FuncTask(CancellationToken, () => path) - .Then(afterPathDetermined) - .Start(); - } - else - { - Logger.Warning("FindExecTask Failure"); - Logger.Error("Git not found"); - } - }); - var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); - var installDetails = new GitInstallDetails(applicationDataPath, true); + var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath(); + if (gitExecutablePath != null && gitExecutablePath.FileExists()) + { + Logger.Trace("Using git install path from settings: {0}", gitExecutablePath); - var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails); - gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken, (b, path) => { - Logger.Trace("GitInstaller Success: {0}", path); - new FuncTask(CancellationToken, () => path) + new FuncTask(CancellationToken, () => gitExecutablePath) .Then(afterPathDetermined) .Start(); - }), new ActionTask(CancellationToken, () => { - Logger.Warning("GitInstaller Failure"); - findExecTask.Start(); - }) ); + } + else + { + Logger.Trace("No git path found in settings"); + + var findExecTask = new FindExecTask("git", CancellationToken) + .Finally((b, ex, path) => { + if (b && path != null) + { + Logger.Trace("FindExecTask Success: {0}", path); + + new FuncTask(CancellationToken, () => path) + .Then(afterPathDetermined) + .Start(); + } + else + { + Logger.Warning("FindExecTask Failure"); + Logger.Error("Git not found"); + } + }); + + var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); + var installDetails = new GitInstallDetails(applicationDataPath, true); + var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails); + + gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken, (b, path) => { + Logger.Trace("GitInstaller Success: {0}", path); + new FuncTask(CancellationToken, () => path) + .Then(afterPathDetermined) + .Start(); + }), new ActionTask(CancellationToken, () => { + Logger.Warning("GitInstaller Failure"); + findExecTask.Start(); + })); + } } public ITask InitializeRepository() From e3d5c4031a93bffcc68807217059a7918492ae56 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 12 Jan 2018 11:27:43 -0500 Subject: [PATCH 0089/1008] Only roll over the log file when it is over 10 MBS when developing --- .../Assets/Editor/GitHub.Unity/EntryPoint.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs index dea9fc30b..51aa84a09 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs @@ -40,10 +40,17 @@ private static void Initialize() var oldLogPath = logPath.Parent.Combine(logPath.FileNameWithoutExtension + "-old" + logPath.ExtensionWithDot); try { - oldLogPath.DeleteIfExists(); - if (logPath.FileExists()) + var shouldRotate = true; +#if DEVELOPER_BUILD + shouldRotate = new FileInfo(logPath).Length > 10 * 1024 * 1024; +#endif + if (shouldRotate) { - logPath.Move(oldLogPath); + oldLogPath.DeleteIfExists(); + if (logPath.FileExists()) + { + logPath.Move(oldLogPath); + } } } catch (Exception ex) From afce3f9a5bbba8fba2a9bf66a120fe98fa20614b Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 12 Jan 2018 11:59:48 -0500 Subject: [PATCH 0090/1008] Basing the display of the loading view on git being present --- .../Assets/Editor/GitHub.Unity/UI/Window.cs | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs index 9ec89ef31..04125b22f 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs @@ -23,8 +23,8 @@ class Window : BaseWindow private const string Window_RepoBranchTooltip = "Active branch"; [NonSerialized] private double notificationClearTime = -1; - [SerializeField] private SubTab changeTab = SubTab.None; - [SerializeField] private SubTab activeTab = SubTab.None; + [SerializeField] private SubTab changeTab = SubTab.Loading; + [SerializeField] private SubTab activeTab = SubTab.Loading; [SerializeField] private InitProjectView initProjectView = new InitProjectView(); [SerializeField] private LoadingView loadingView = new LoadingView(); [SerializeField] private BranchesView branchesView = new BranchesView(); @@ -86,26 +86,14 @@ public override void Initialize(IApplicationManager applicationManager) { base.Initialize(applicationManager); - gitExecutableIsSet = Environment.GitExecutablePath != null; - - if (ApplicationCache.Instance.FirstRun && !gitExecutableIsSet && activeTab != SubTab.Loading) - { - changeTab = activeTab = SubTab.Loading; - } - else if(gitExecutableIsSet) + gitExecutableIsSet = !string.IsNullOrEmpty(Environment.GitExecutablePath); + if (gitExecutableIsSet) { - if (HasRepository) + if (!HasRepository) { if (activeTab == SubTab.Loading) { - changeTab = SubTab.Changes; - UpdateActiveTab(); - } - } - else - { - if (activeTab != SubTab.InitProject && activeTab != SubTab.Settings) - { + Logger.Trace("Initialze set all tabs to InitProject"); changeTab = activeTab = SubTab.InitProject; } } @@ -164,10 +152,28 @@ public override void OnRepositoryChanged(IRepository oldRepository) DetachHandlers(oldRepository); AttachHandlers(Repository); - if (Repository != null && activeTab == SubTab.InitProject) + if (gitExecutableIsSet) { - changeTab = SubTab.History; - UpdateActiveTab(); + if (HasRepository) + { + if (activeTab == SubTab.InitProject) + { + Logger.Trace("OnRepositoryChanged set changeTab to History"); + + changeTab = SubTab.History; + UpdateActiveTab(); + } + } + else + { + if (activeTab == SubTab.Loading) + { + Logger.Trace("OnRepositoryChanged set changeTab to InitProject"); + + changeTab = SubTab.InitProject; + UpdateActiveTab(); + } + } } } @@ -190,7 +196,7 @@ public override void OnUI() { base.OnUI(); - if(ApplicationCache.Instance.FirstRun && gitExecutableIsSet || !ApplicationCache.Instance.FirstRun) + if(gitExecutableIsSet) { if (HasRepository) { From 194806506869855147371e9f3e31f32c7db8f046 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Tue, 16 Jan 2018 19:20:53 +0100 Subject: [PATCH 0091/1008] Bump System.Net.Http and Octokit builds to pick up type conflict fix Fixes #503 When running System.Net.Http in Unity with the 4.6 experimental runtime, Unity will load Mono's version of System.Net.Http, which causes type conflicts all over the place given that both dlls are running side by side. Easiest way of avoiding that is to move all the classes in System.Net.Http into its own namespace - "DotNetHttp35". Also renamed the dll to reflect the namespace change. See https://github.com/github-for-unity/dotnet-httpclient35/commit/8566426a9217 --- common/build.targets | 2 +- lib/dotnet-httpClient35/DotNetHttp35.dll | 3 +++ lib/dotnet-httpClient35/DotNetHttp35.dll.mdb | 3 +++ lib/dotnet-httpClient35/System.Net.Http.dll | 3 --- lib/dotnet-httpClient35/System.Net.Http.dll.mdb | 3 --- lib/dotnet-httpClient35/md5sums.txt | 4 ++-- lib/octokit.net/Octokit.dll | 2 +- lib/octokit.net/Octokit.dll.mdb | 4 ++-- lib/octokit.net/md5sums.txt | 4 ++-- script | 2 +- .../{System.Net.Http.dll.meta => DotNetHttp35.dll.meta} | 0 11 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 lib/dotnet-httpClient35/DotNetHttp35.dll create mode 100644 lib/dotnet-httpClient35/DotNetHttp35.dll.mdb delete mode 100644 lib/dotnet-httpClient35/System.Net.Http.dll delete mode 100644 lib/dotnet-httpClient35/System.Net.Http.dll.mdb rename unity/PackageProject/Assets/Plugins/GitHub/Editor/{System.Net.Http.dll.meta => DotNetHttp35.dll.meta} (100%) diff --git a/common/build.targets b/common/build.targets index cb88330c3..c80db3b01 100644 --- a/common/build.targets +++ b/common/build.targets @@ -30,7 +30,7 @@ $(SolutionDir)lib\octokit.net\Octokit.dll - $(SolutionDir)lib\dotnet-httpclient35\System.Net.Http.dll + $(SolutionDir)lib\dotnet-httpclient35\DotNetHttp35.dll diff --git a/lib/dotnet-httpClient35/DotNetHttp35.dll b/lib/dotnet-httpClient35/DotNetHttp35.dll new file mode 100644 index 000000000..7e68fe5e3 --- /dev/null +++ b/lib/dotnet-httpClient35/DotNetHttp35.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6daaf4e57900d0a092a94dbe10aca3796ad7496f40347112b602a6ff6dcf0275 +size 123392 diff --git a/lib/dotnet-httpClient35/DotNetHttp35.dll.mdb b/lib/dotnet-httpClient35/DotNetHttp35.dll.mdb new file mode 100644 index 000000000..fdd070e10 --- /dev/null +++ b/lib/dotnet-httpClient35/DotNetHttp35.dll.mdb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:be437526dd7332f42ea2c10cf9548e5c8b4f3f0fc735d584294d72ba4d592e81 +size 47000 diff --git a/lib/dotnet-httpClient35/System.Net.Http.dll b/lib/dotnet-httpClient35/System.Net.Http.dll deleted file mode 100644 index 69fee1021..000000000 --- a/lib/dotnet-httpClient35/System.Net.Http.dll +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fd1e590c79fa453c5722bd645ef037d5f7748177bab14bd794981adc11a06a0 -size 123904 diff --git a/lib/dotnet-httpClient35/System.Net.Http.dll.mdb b/lib/dotnet-httpClient35/System.Net.Http.dll.mdb deleted file mode 100644 index 5f13b0ccb..000000000 --- a/lib/dotnet-httpClient35/System.Net.Http.dll.mdb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:df057b70add2c6488614a273236cb07d5b971026de36c5b9a3f044a547af75f2 -size 47752 diff --git a/lib/dotnet-httpClient35/md5sums.txt b/lib/dotnet-httpClient35/md5sums.txt index e99ef3233..4f97ea53b 100644 --- a/lib/dotnet-httpClient35/md5sums.txt +++ b/lib/dotnet-httpClient35/md5sums.txt @@ -1,2 +1,2 @@ -e15a0894ef162ec53566fa9c8211e583 *System.Net.Http.dll -161847a9a61eb3cdab7a7706e83265a1 *System.Net.Http.dll.mdb +0b299a0c541e19a6205f1265da27e540 *DotNetHttp35.dll +4698f765de6671c08befd610eb254013 *DotNetHttp35.dll.mdb diff --git a/lib/octokit.net/Octokit.dll b/lib/octokit.net/Octokit.dll index 9ecfd9fce..fd797251f 100644 --- a/lib/octokit.net/Octokit.dll +++ b/lib/octokit.net/Octokit.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:003fb61b6517b43d4ce412070bede800af20a161bcf8cb9cbcbac38aed1075da +oid sha256:cb297646723b439a8755e1b967a9f5850dd9c50f1126f1e6ba9ddd8677188f84 size 741888 diff --git a/lib/octokit.net/Octokit.dll.mdb b/lib/octokit.net/Octokit.dll.mdb index 041f8dd04..ef51d4875 100644 --- a/lib/octokit.net/Octokit.dll.mdb +++ b/lib/octokit.net/Octokit.dll.mdb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe50d2c5d38b8dd9407a9053f46b4cec638959637d690ff169cf7aea2db4a187 -size 288546 +oid sha256:ebdf240eb57a1154884fdc1ae5962e0d2af5f0c663fe5cb8f1897fa5c82b7218 +size 283050 diff --git a/lib/octokit.net/md5sums.txt b/lib/octokit.net/md5sums.txt index 60441e277..33bc5f2df 100644 --- a/lib/octokit.net/md5sums.txt +++ b/lib/octokit.net/md5sums.txt @@ -1,2 +1,2 @@ -ecb6930236469c41a36dee6d84fcab7a *Octokit.dll -2a41d96c1ad9229d8ff2f46b8847ec6a *Octokit.dll.mdb +352dbd9611f700a9dbde52999752d88d *Octokit.dll +883c04490791e7d4f63c2e918233dc55 *Octokit.dll.mdb diff --git a/script b/script index 591ff936a..a3601bd25 160000 --- a/script +++ b/script @@ -1 +1 @@ -Subproject commit 591ff936add8cc2e165712b523a8597a66233478 +Subproject commit a3601bd256ce6498b222914676b9b6e2e04ac7c2 diff --git a/unity/PackageProject/Assets/Plugins/GitHub/Editor/System.Net.Http.dll.meta b/unity/PackageProject/Assets/Plugins/GitHub/Editor/DotNetHttp35.dll.meta similarity index 100% rename from unity/PackageProject/Assets/Plugins/GitHub/Editor/System.Net.Http.dll.meta rename to unity/PackageProject/Assets/Plugins/GitHub/Editor/DotNetHttp35.dll.meta From d714c7dcf06e4e93469e1232b7dec9b9c8c55b64 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 16 Jan 2018 17:48:10 -0500 Subject: [PATCH 0092/1008] Bump version to 0.26.1 --- common/SolutionInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/SolutionInfo.cs b/common/SolutionInfo.cs index eb4e6f5b3..902f73e57 100644 --- a/common/SolutionInfo.cs +++ b/common/SolutionInfo.cs @@ -31,6 +31,6 @@ namespace System { internal static class AssemblyVersionInformation { - internal const string Version = "0.26.0"; + internal const string Version = "0.26.1"; } } From 634ae54f23700f8a42ad438bfed340778cb7b52c Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Tue, 16 Jan 2018 19:20:53 +0100 Subject: [PATCH 0093/1008] Bump System.Net.Http and Octokit builds to pick up type conflict fix Fixes #503 When running System.Net.Http in Unity with the 4.6 experimental runtime, Unity will load Mono's version of System.Net.Http, which causes type conflicts all over the place given that both dlls are running side by side. Easiest way of avoiding that is to move all the classes in System.Net.Http into its own namespace - "DotNetHttp35". Also renamed the dll to reflect the namespace change. See https://github.com/github-for-unity/dotnet-httpclient35/commit/8566426a9217 --- common/build.targets | 2 +- lib/dotnet-httpClient35/DotNetHttp35.dll | 3 +++ lib/dotnet-httpClient35/DotNetHttp35.dll.mdb | 3 +++ lib/dotnet-httpClient35/System.Net.Http.dll | 3 --- lib/dotnet-httpClient35/System.Net.Http.dll.mdb | 3 --- lib/dotnet-httpClient35/md5sums.txt | 4 ++-- lib/octokit.net/Octokit.dll | 2 +- lib/octokit.net/Octokit.dll.mdb | 4 ++-- lib/octokit.net/md5sums.txt | 4 ++-- script | 2 +- .../{System.Net.Http.dll.meta => DotNetHttp35.dll.meta} | 0 11 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 lib/dotnet-httpClient35/DotNetHttp35.dll create mode 100644 lib/dotnet-httpClient35/DotNetHttp35.dll.mdb delete mode 100644 lib/dotnet-httpClient35/System.Net.Http.dll delete mode 100644 lib/dotnet-httpClient35/System.Net.Http.dll.mdb rename unity/PackageProject/Assets/Plugins/GitHub/Editor/{System.Net.Http.dll.meta => DotNetHttp35.dll.meta} (100%) diff --git a/common/build.targets b/common/build.targets index cb88330c3..c80db3b01 100644 --- a/common/build.targets +++ b/common/build.targets @@ -30,7 +30,7 @@ $(SolutionDir)lib\octokit.net\Octokit.dll - $(SolutionDir)lib\dotnet-httpclient35\System.Net.Http.dll + $(SolutionDir)lib\dotnet-httpclient35\DotNetHttp35.dll diff --git a/lib/dotnet-httpClient35/DotNetHttp35.dll b/lib/dotnet-httpClient35/DotNetHttp35.dll new file mode 100644 index 000000000..7e68fe5e3 --- /dev/null +++ b/lib/dotnet-httpClient35/DotNetHttp35.dll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6daaf4e57900d0a092a94dbe10aca3796ad7496f40347112b602a6ff6dcf0275 +size 123392 diff --git a/lib/dotnet-httpClient35/DotNetHttp35.dll.mdb b/lib/dotnet-httpClient35/DotNetHttp35.dll.mdb new file mode 100644 index 000000000..fdd070e10 --- /dev/null +++ b/lib/dotnet-httpClient35/DotNetHttp35.dll.mdb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:be437526dd7332f42ea2c10cf9548e5c8b4f3f0fc735d584294d72ba4d592e81 +size 47000 diff --git a/lib/dotnet-httpClient35/System.Net.Http.dll b/lib/dotnet-httpClient35/System.Net.Http.dll deleted file mode 100644 index 69fee1021..000000000 --- a/lib/dotnet-httpClient35/System.Net.Http.dll +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fd1e590c79fa453c5722bd645ef037d5f7748177bab14bd794981adc11a06a0 -size 123904 diff --git a/lib/dotnet-httpClient35/System.Net.Http.dll.mdb b/lib/dotnet-httpClient35/System.Net.Http.dll.mdb deleted file mode 100644 index 5f13b0ccb..000000000 --- a/lib/dotnet-httpClient35/System.Net.Http.dll.mdb +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:df057b70add2c6488614a273236cb07d5b971026de36c5b9a3f044a547af75f2 -size 47752 diff --git a/lib/dotnet-httpClient35/md5sums.txt b/lib/dotnet-httpClient35/md5sums.txt index e99ef3233..4f97ea53b 100644 --- a/lib/dotnet-httpClient35/md5sums.txt +++ b/lib/dotnet-httpClient35/md5sums.txt @@ -1,2 +1,2 @@ -e15a0894ef162ec53566fa9c8211e583 *System.Net.Http.dll -161847a9a61eb3cdab7a7706e83265a1 *System.Net.Http.dll.mdb +0b299a0c541e19a6205f1265da27e540 *DotNetHttp35.dll +4698f765de6671c08befd610eb254013 *DotNetHttp35.dll.mdb diff --git a/lib/octokit.net/Octokit.dll b/lib/octokit.net/Octokit.dll index 9ecfd9fce..fd797251f 100644 --- a/lib/octokit.net/Octokit.dll +++ b/lib/octokit.net/Octokit.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:003fb61b6517b43d4ce412070bede800af20a161bcf8cb9cbcbac38aed1075da +oid sha256:cb297646723b439a8755e1b967a9f5850dd9c50f1126f1e6ba9ddd8677188f84 size 741888 diff --git a/lib/octokit.net/Octokit.dll.mdb b/lib/octokit.net/Octokit.dll.mdb index 041f8dd04..ef51d4875 100644 --- a/lib/octokit.net/Octokit.dll.mdb +++ b/lib/octokit.net/Octokit.dll.mdb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe50d2c5d38b8dd9407a9053f46b4cec638959637d690ff169cf7aea2db4a187 -size 288546 +oid sha256:ebdf240eb57a1154884fdc1ae5962e0d2af5f0c663fe5cb8f1897fa5c82b7218 +size 283050 diff --git a/lib/octokit.net/md5sums.txt b/lib/octokit.net/md5sums.txt index 60441e277..33bc5f2df 100644 --- a/lib/octokit.net/md5sums.txt +++ b/lib/octokit.net/md5sums.txt @@ -1,2 +1,2 @@ -ecb6930236469c41a36dee6d84fcab7a *Octokit.dll -2a41d96c1ad9229d8ff2f46b8847ec6a *Octokit.dll.mdb +352dbd9611f700a9dbde52999752d88d *Octokit.dll +883c04490791e7d4f63c2e918233dc55 *Octokit.dll.mdb diff --git a/script b/script index 591ff936a..a3601bd25 160000 --- a/script +++ b/script @@ -1 +1 @@ -Subproject commit 591ff936add8cc2e165712b523a8597a66233478 +Subproject commit a3601bd256ce6498b222914676b9b6e2e04ac7c2 diff --git a/unity/PackageProject/Assets/Plugins/GitHub/Editor/System.Net.Http.dll.meta b/unity/PackageProject/Assets/Plugins/GitHub/Editor/DotNetHttp35.dll.meta similarity index 100% rename from unity/PackageProject/Assets/Plugins/GitHub/Editor/System.Net.Http.dll.meta rename to unity/PackageProject/Assets/Plugins/GitHub/Editor/DotNetHttp35.dll.meta From 131f313fd4e59de0c92f0cd2171e82126329630a Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 25 Jan 2018 15:06:59 -0500 Subject: [PATCH 0094/1008] Adding several new data points to track in Unity --- .../Application/ApplicationManagerBase.cs | 3 +- src/GitHub.Api/Metrics/IUsageTracker.cs | 28 +++- src/GitHub.Api/Metrics/UsageModel.cs | 10 ++ src/GitHub.Api/Metrics/UsageTracker.cs | 138 ++++++++++++++++-- .../GitHub.Unity/UI/AuthenticationView.cs | 5 + .../Editor/GitHub.Unity/UI/BranchesView.cs | 5 +- .../Editor/GitHub.Unity/UI/ChangesView.cs | 5 + .../Editor/GitHub.Unity/UI/HistoryView.cs | 6 + 8 files changed, 181 insertions(+), 19 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 63c4d67bc..2c53665fc 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -120,6 +120,7 @@ public ITask InitializeRepository() Environment.InitializeRepository(); RestartRepository(); }) + .ThenInUI(UsageTracker.IncrementNumberOfProjectsInitialized) .ThenInUI(InitializeUI); return task; } @@ -179,7 +180,7 @@ protected void SetupMetrics(string unityVersion, bool firstRun) if (firstRun) { - UsageTracker.IncrementLaunchCount(); + UsageTracker.IncrementNumberOfStartups(); } } diff --git a/src/GitHub.Api/Metrics/IUsageTracker.cs b/src/GitHub.Api/Metrics/IUsageTracker.cs index 18b4584ee..0c5522b71 100644 --- a/src/GitHub.Api/Metrics/IUsageTracker.cs +++ b/src/GitHub.Api/Metrics/IUsageTracker.cs @@ -6,15 +6,33 @@ namespace GitHub.Unity public interface IUsageTracker { bool Enabled { get; set; } - void IncrementLaunchCount(); + void IncrementNumberOfStartups(); + void IncrementNumberOfCommits(); + void IncrementNumberOfFetches(); + void IncrementNumberOfPushes(); + void IncrementNumberOfPulls(); + void IncrementNumberOfAuthentications(); + void IncrementNumberOfProjectsInitialized(); + void IncrementNumberOfLocalBranchCreations(); + void IncrementNumberOfLocalBranchDeletions(); + void IncrementNumberOfLocalBranchCheckouts(); + void IncrementNumberOfRemoteBranchCheckouts(); } class NullUsageTracker : IUsageTracker { public bool Enabled { get; set; } - - public void IncrementLaunchCount(){ } - public void SetMetricsService(IMetricsService instance) - { } + public void IncrementNumberOfStartups() { } + public void IncrementNumberOfCommits() { } + public void IncrementNumberOfFetches() { } + public void IncrementNumberOfPushes() { } + public void IncrementNumberOfPulls() { } + public void IncrementNumberOfAuthentications() { } + public void IncrementNumberOfProjectsInitialized() { } + public void IncrementNumberOfLocalBranchCreations() { } + public void IncrementNumberOfLocalBranchDeletions() { } + public void IncrementNumberOfLocalBranchCheckouts() { } + public void IncrementNumberOfRemoteBranchCheckouts() { } + public void SetMetricsService(IMetricsService instance) { } } } diff --git a/src/GitHub.Api/Metrics/UsageModel.cs b/src/GitHub.Api/Metrics/UsageModel.cs index 66ae88362..2d9011115 100644 --- a/src/GitHub.Api/Metrics/UsageModel.cs +++ b/src/GitHub.Api/Metrics/UsageModel.cs @@ -12,6 +12,16 @@ public class Usage public string UnityVersion { get; set; } public string Lang { get; set; } public int NumberOfStartups { get; set; } + public int NumberOfCommits { get; set; } + public int NumberOfFetches { get; set; } + public int NumberOfPushes { get; set; } + public int NumberOfPulls { get; set; } + public int NumberOfProjectsInitialized { get; set; } + public int NumberOfAuthentications { get; set; } + public int NumberOfLocalBranchCreations { get; set; } + public int NumberOfLocalBranchDeletion { get; set; } + public int NumberOfLocalBranchCheckouts { get; set; } + public int NumberOfRemoteBranchCheckouts { get; set; } } class UsageModel diff --git a/src/GitHub.Api/Metrics/UsageTracker.cs b/src/GitHub.Api/Metrics/UsageTracker.cs index 30e90e44e..9d38d4eaa 100644 --- a/src/GitHub.Api/Metrics/UsageTracker.cs +++ b/src/GitHub.Api/Metrics/UsageTracker.cs @@ -104,12 +104,11 @@ private void RunTimer(int seconds) }, null, seconds * 1000, Timeout.Infinite); } - private async Task SendUsage() { Logger.Trace("SendUsage"); - var usage = LoadUsage(); + var usageStore = LoadUsage(); if (metricsService == null) { @@ -117,7 +116,7 @@ private async Task SendUsage() return; } - if (usage.LastUpdated.Date != DateTimeOffset.UtcNow.Date) + if (usageStore.LastUpdated.Date != DateTimeOffset.UtcNow.Date) { Logger.Trace("Sending Usage"); @@ -125,7 +124,7 @@ private async Task SendUsage() var beforeDate = currentTimeOffset.Date; var success = false; - var extractReports = usage.Model.SelectReports(beforeDate); + var extractReports = usageStore.Model.SelectReports(beforeDate); if (!extractReports.Any()) { Logger.Trace("No items to send"); @@ -151,24 +150,139 @@ private async Task SendUsage() if (success) { - usage.Model.RemoveReports(beforeDate); - usage.LastUpdated = currentTimeOffset; - SaveUsage(usage); + usageStore.Model.RemoveReports(beforeDate); + usageStore.LastUpdated = currentTimeOffset; + SaveUsage(usageStore); } } } - public void IncrementLaunchCount() + private Usage GetCurrentUsage(UsageStore usageStore) { - var usageStore = LoadUsage(); - var usage = usageStore.Model.GetCurrentUsage(); - usage.NumberOfStartups++; usage.UnityVersion = unityVersion; usage.Lang = CultureInfo.InstalledUICulture.IetfLanguageTag; usage.AppVersion = AppConfiguration.AssemblyName.Version.ToString(); + return usage; + } + + public void IncrementNumberOfStartups() + { + var usageStore = LoadUsage(); + var usage = GetCurrentUsage(usageStore); + + usage.NumberOfStartups++; + Logger.Trace("NumberOfStartups:{0} Date:{1}", usage.NumberOfStartups, usage.Date); + + SaveUsage(usageStore); + } + + public void IncrementNumberOfCommits() + { + var usageStore = LoadUsage(); + var usage = GetCurrentUsage(usageStore); + + usage.NumberOfCommits++; + Logger.Trace("NumberOfCommits:{0} Date:{1}", usage.NumberOfCommits, usage.Date); + + SaveUsage(usageStore); + } + + public void IncrementNumberOfFetches() + { + var usageStore = LoadUsage(); + var usage = GetCurrentUsage(usageStore); + + usage.NumberOfFetches++; + Logger.Trace("NumberOfFetches:{0} Date:{1}", usage.NumberOfFetches, usage.Date); + + SaveUsage(usageStore); + } + + public void IncrementNumberOfPushes() + { + var usageStore = LoadUsage(); + var usage = GetCurrentUsage(usageStore); + + usage.NumberOfPushes++; + Logger.Trace("NumberOfPushes:{0} Date:{1}", usage.NumberOfPushes, usage.Date); + + SaveUsage(usageStore); + } + + public void IncrementNumberOfProjectsInitialized() + { + var usageStore = LoadUsage(); + var usage = GetCurrentUsage(usageStore); + + usage.NumberOfProjectsInitialized++; + Logger.Trace("NumberOfProjectsInitialized:{0} Date:{1}", usage.NumberOfProjectsInitialized, usage.Date); + + SaveUsage(usageStore); + } + + public void IncrementNumberOfLocalBranchCreations() + { + var usageStore = LoadUsage(); + var usage = GetCurrentUsage(usageStore); + + usage.NumberOfLocalBranchCreations++; + Logger.Trace("NumberOfLocalBranchCreations:{0} Date:{1}", usage.NumberOfLocalBranchCreations, usage.Date); + + SaveUsage(usageStore); + } + + public void IncrementNumberOfLocalBranchDeletions() + { + var usageStore = LoadUsage(); + var usage = GetCurrentUsage(usageStore); + + usage.NumberOfLocalBranchDeletion++; + Logger.Trace("NumberOfLocalBranchDeletion:{0} Date:{1}", usage.NumberOfLocalBranchDeletion, usage.Date); + + SaveUsage(usageStore); + } + + public void IncrementNumberOfLocalBranchCheckouts() + { + var usageStore = LoadUsage(); + var usage = GetCurrentUsage(usageStore); + + usage.NumberOfLocalBranchCheckouts++; + Logger.Trace("NumberOfLocalBranchCheckouts:{0} Date:{1}", usage.NumberOfLocalBranchCheckouts, usage.Date); + + SaveUsage(usageStore); + } + + public void IncrementNumberOfRemoteBranchCheckouts() + { + var usageStore = LoadUsage(); + var usage = GetCurrentUsage(usageStore); + + usage.NumberOfRemoteBranchCheckouts++; + Logger.Trace("NumberOfRemoteBranchCheckouts:{0} Date:{1}", usage.NumberOfRemoteBranchCheckouts, usage.Date); + + SaveUsage(usageStore); + } + + public void IncrementNumberOfPulls() + { + var usageStore = LoadUsage(); + var usage = GetCurrentUsage(usageStore); + + usage.NumberOfPulls++; + Logger.Trace("NumberOfPulls:{0} Date:{1}", usage.NumberOfPulls, usage.Date); + + SaveUsage(usageStore); + } + + public void IncrementNumberOfAuthentications() + { + var usageStore = LoadUsage(); + var usage = GetCurrentUsage(usageStore); - Logger.Trace("IncrementLaunchCount Date:{0} NumberOfStartups:{1}", usage.Date, usage.NumberOfStartups); + usage.NumberOfAuthentications++; + Logger.Trace("NumberOfAuthentications:{0} Date:{1}", usage.NumberOfAuthentications, usage.Date); SaveUsage(usageStore); } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs index c7795c05a..b99f6bf2e 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using UnityEngine; using UnityEditor; @@ -213,6 +214,10 @@ private void DoResult(bool success, string msg) if (success == true) { + new ActionTask(CancellationToken.None, () => { + EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfAuthentications(); + }) { Affinity = TaskAffinity.UI }.Start(); + Clear(); Finish(true); } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs index a4bfff22e..0dbbd93e2 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs @@ -272,6 +272,7 @@ private void OnButtonBarGUI() { if (success) { + EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfLocalBranchCreations(); Redraw(); } else @@ -439,6 +440,7 @@ private void CheckoutRemoteBranch(string branch) GitClient.CreateBranch(branchName, branch).FinallyInUI((success, e) => { if (success) { + EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfRemoteBranchCheckouts(); Redraw(); } else @@ -459,6 +461,7 @@ private void SwitchBranch(string branch) GitClient.SwitchBranch(branch).FinallyInUI((success, e) => { if (success) { + EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfLocalBranchCheckouts(); Redraw(); } else @@ -475,7 +478,7 @@ private void DeleteLocalBranch(string branch) var dialogMessage = string.Format(DeleteBranchMessageFormatString, branch); if (EditorUtility.DisplayDialog(DeleteBranchTitle, dialogMessage, DeleteBranchButton, CancelButtonLabel)) { - GitClient.DeleteBranch(branch, true).Start(); + GitClient.DeleteBranch(branch, true).ThenInUI(EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfLocalBranchDeletions).Start(); } } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs index 0acdfb56b..86cf8c858 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs @@ -318,6 +318,11 @@ private void Commit() addTask .FinallyInUI((b, exception) => { + if (b) + { + EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfCommits(); + } + commitMessage = ""; commitBody = ""; SetBusy(false); diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs index b2da0f974..658df2a25 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs @@ -681,6 +681,8 @@ private void Pull() .FinallyInUI((success, e) => { if (success) { + EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfPulls(); + EditorUtility.DisplayDialog(Localization.PullActionTitle, String.Format(Localization.PullSuccessDescription, currentRemoteName), Localization.Ok); @@ -703,6 +705,8 @@ private void Push() .FinallyInUI((success, e) => { if (success) { + EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfPushes(); + EditorUtility.DisplayDialog(Localization.PushActionTitle, String.Format(Localization.PushSuccessDescription, currentRemoteName), Localization.Ok); @@ -722,6 +726,8 @@ private void Fetch() Repository .Fetch() .FinallyInUI((success, e) => { + EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfFetches(); + if (!success) { EditorUtility.DisplayDialog(FetchActionTitle, FetchFailureDescription, From 861a27fde2dbcde776276ddbfaaf2ba0504c5426 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 25 Jan 2018 15:07:53 -0500 Subject: [PATCH 0095/1008] If developing data won't send but it should still save --- src/GitHub.Api/Metrics/UsageTracker.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/GitHub.Api/Metrics/UsageTracker.cs b/src/GitHub.Api/Metrics/UsageTracker.cs index 9d38d4eaa..b66e7c204 100644 --- a/src/GitHub.Api/Metrics/UsageTracker.cs +++ b/src/GitHub.Api/Metrics/UsageTracker.cs @@ -71,11 +71,6 @@ private UsageStore LoadUsage() private void SaveUsage(UsageStore store) { - if (!Enabled) - { - return; - } - var pathString = storePath.ToString(); Logger.Trace("SaveUsage: \"{0}\"", pathString); From 481a56e52b2c55454a1a5aa4abf8c77ea883e88e Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 25 Jan 2018 16:52:50 -0500 Subject: [PATCH 0096/1008] Adding CurrentLang --- src/GitHub.Api/Metrics/UsageModel.cs | 1 + src/GitHub.Api/Metrics/UsageTracker.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/GitHub.Api/Metrics/UsageModel.cs b/src/GitHub.Api/Metrics/UsageModel.cs index 2d9011115..7ee9cb670 100644 --- a/src/GitHub.Api/Metrics/UsageModel.cs +++ b/src/GitHub.Api/Metrics/UsageModel.cs @@ -11,6 +11,7 @@ public class Usage public string AppVersion { get; set; } public string UnityVersion { get; set; } public string Lang { get; set; } + public string CurrentLang { get; set; } public int NumberOfStartups { get; set; } public int NumberOfCommits { get; set; } public int NumberOfFetches { get; set; } diff --git a/src/GitHub.Api/Metrics/UsageTracker.cs b/src/GitHub.Api/Metrics/UsageTracker.cs index b66e7c204..9f2cd9e61 100644 --- a/src/GitHub.Api/Metrics/UsageTracker.cs +++ b/src/GitHub.Api/Metrics/UsageTracker.cs @@ -158,6 +158,7 @@ private Usage GetCurrentUsage(UsageStore usageStore) usage.UnityVersion = unityVersion; usage.Lang = CultureInfo.InstalledUICulture.IetfLanguageTag; usage.AppVersion = AppConfiguration.AssemblyName.Version.ToString(); + usage.CurrentLang = CultureInfo.CurrentCulture.IetfLanguageTag; return usage; } From c8d6db5e2942464de19998ca0f26d2c2a748019c Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 25 Jan 2018 16:53:50 -0500 Subject: [PATCH 0097/1008] Grouping data records by GitHub for Unity version and Unity version --- src/GitHub.Api/Metrics/UsageModel.cs | 17 ++++++++++++++--- src/GitHub.Api/Metrics/UsageTracker.cs | 4 +--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/GitHub.Api/Metrics/UsageModel.cs b/src/GitHub.Api/Metrics/UsageModel.cs index 7ee9cb670..e057fbac1 100644 --- a/src/GitHub.Api/Metrics/UsageModel.cs +++ b/src/GitHub.Api/Metrics/UsageModel.cs @@ -32,12 +32,18 @@ class UsageModel private Usage currentUsage; - public Usage GetCurrentUsage() + public Usage GetCurrentUsage(string appVersion, string unityVersion) { + Guard.ArgumentNotNullOrWhiteSpace(appVersion, "appVersion"); + Guard.ArgumentNotNullOrWhiteSpace(unityVersion, "unityVersion"); + var date = DateTime.UtcNow.Date; if (currentUsage == null) { - currentUsage = Reports.FirstOrDefault(usage => usage.Date == date); + currentUsage = Reports + .FirstOrDefault(usage => usage.Date == date + && usage.AppVersion == appVersion + && usage.UnityVersion == unityVersion); } if (currentUsage?.Date == date) @@ -48,7 +54,12 @@ public Usage GetCurrentUsage() } else { - currentUsage = new Usage { Date = date, Guid = Guid }; + currentUsage = new Usage { + Date = date, + Guid = Guid, + AppVersion = appVersion, + UnityVersion = unityVersion, + }; Reports.Add(currentUsage); } diff --git a/src/GitHub.Api/Metrics/UsageTracker.cs b/src/GitHub.Api/Metrics/UsageTracker.cs index 9f2cd9e61..dc624ed6f 100644 --- a/src/GitHub.Api/Metrics/UsageTracker.cs +++ b/src/GitHub.Api/Metrics/UsageTracker.cs @@ -154,10 +154,8 @@ private async Task SendUsage() private Usage GetCurrentUsage(UsageStore usageStore) { - var usage = usageStore.Model.GetCurrentUsage(); - usage.UnityVersion = unityVersion; + var usage = usageStore.Model.GetCurrentUsage(AppConfiguration.AssemblyName.Version.ToString(), unityVersion); usage.Lang = CultureInfo.InstalledUICulture.IetfLanguageTag; - usage.AppVersion = AppConfiguration.AssemblyName.Version.ToString(); usage.CurrentLang = CultureInfo.CurrentCulture.IetfLanguageTag; return usage; } From 0f4efef28caaf9c71a99e96a6e355221d66e2fee Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 25 Jan 2018 16:54:09 -0500 Subject: [PATCH 0098/1008] Adding Unity version to the log file --- src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs index 51aa84a09..924a9e7f6 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs @@ -62,7 +62,7 @@ private static void Initialize() } Logging.LogAdapter = new FileLogAdapter(logPath); - Logging.Info("Initializing GitHub for Unity version " + ApplicationInfo.Version); + Logging.Info("Initializing GitHubForUnity:v{0} Unity:v{1}", ApplicationInfo.Version, Environment.UnityVersion); ApplicationManager.Run(ApplicationCache.Instance.FirstRun); } From 20b053c66ee4b8f6d60ef55c53bd31ef1cbaeac2 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 26 Jan 2018 09:04:59 -0500 Subject: [PATCH 0099/1008] Attaching to GitUserCache events at a time when they might actually be fired --- src/GitHub.Api/Git/Repository.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 6a69c7444..8de636c76 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -649,9 +649,6 @@ public class User : IUser public User(ICacheContainer cacheContainer) { this.cacheContainer = cacheContainer; - - cacheContainer.GitUserCache.CacheInvalidated += GitUserCacheOnCacheInvalidated; - cacheContainer.GitUserCache.CacheUpdated += GitUserCacheOnCacheUpdated; } public void CheckUserChangedEvent(CacheUpdateEvent cacheUpdateEvent) @@ -677,6 +674,9 @@ public void Initialize(IGitClient client) Logger.Trace("Initialize"); gitClient = client; + + cacheContainer.GitUserCache.CacheInvalidated += GitUserCacheOnCacheInvalidated; + cacheContainer.GitUserCache.CacheUpdated += GitUserCacheOnCacheUpdated; cacheContainer.GitUserCache.ValidateData(); } From c69cf53465d9786d5e6802fb7cbdd0087ba4c603 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 26 Jan 2018 09:26:58 -0500 Subject: [PATCH 0100/1008] Formatting fix --- .../Assets/Editor/GitHub.Unity/UI/BranchesView.cs | 5 ++++- .../Assets/Editor/GitHub.Unity/UI/HistoryView.cs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs index 0dbbd93e2..a8328629b 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs @@ -478,7 +478,10 @@ private void DeleteLocalBranch(string branch) var dialogMessage = string.Format(DeleteBranchMessageFormatString, branch); if (EditorUtility.DisplayDialog(DeleteBranchTitle, dialogMessage, DeleteBranchButton, CancelButtonLabel)) { - GitClient.DeleteBranch(branch, true).ThenInUI(EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfLocalBranchDeletions).Start(); + GitClient + .DeleteBranch(branch, true) + .ThenInUI(EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfLocalBranchDeletions) + .Start(); } } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs index 658df2a25..abd1a78da 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs @@ -681,7 +681,7 @@ private void Pull() .FinallyInUI((success, e) => { if (success) { - EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfPulls(); + EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfPulls(); EditorUtility.DisplayDialog(Localization.PullActionTitle, String.Format(Localization.PullSuccessDescription, currentRemoteName), From 096d1699debdce6f9f6cefbb0467c31428e597b0 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 26 Jan 2018 12:22:21 -0500 Subject: [PATCH 0101/1008] Adding version for easier parsing --- src/GitHub.Api/Metrics/UsageModel.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/GitHub.Api/Metrics/UsageModel.cs b/src/GitHub.Api/Metrics/UsageModel.cs index e057fbac1..6bca9effa 100644 --- a/src/GitHub.Api/Metrics/UsageModel.cs +++ b/src/GitHub.Api/Metrics/UsageModel.cs @@ -8,6 +8,7 @@ public class Usage { public string Guid { get; set; } public DateTime Date { get; set; } + public int Version { get; set; } public string AppVersion { get; set; } public string UnityVersion { get; set; } public string Lang { get; set; } @@ -55,6 +56,7 @@ public Usage GetCurrentUsage(string appVersion, string unityVersion) else { currentUsage = new Usage { + Version = 2, Date = date, Guid = Guid, AppVersion = appVersion, From 4eff8ae4b2d49ecf61f8d4870fccaf72fe7a4655 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 31 Jan 2018 09:17:03 -0500 Subject: [PATCH 0102/1008] Making the log entry a bit more parseable --- src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs index 924a9e7f6..0d94f8f6d 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs @@ -62,7 +62,7 @@ private static void Initialize() } Logging.LogAdapter = new FileLogAdapter(logPath); - Logging.Info("Initializing GitHubForUnity:v{0} Unity:v{1}", ApplicationInfo.Version, Environment.UnityVersion); + Logging.Info("Initializing GitHubForUnity:'v{0}' Unity:'v{1}'", ApplicationInfo.Version, Environment.UnityVersion); ApplicationManager.Run(ApplicationCache.Instance.FirstRun); } From 9157a894bc63d4c2e92d4f46a0e199d508f2e7de Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 31 Jan 2018 09:18:26 -0500 Subject: [PATCH 0103/1008] Removing switch to main thread This code is already running on the main thread --- .../Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs index b99f6bf2e..8362ccfd0 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs @@ -212,11 +212,9 @@ private void DoResult(bool success, string msg) isBusy = false; - if (success == true) + if (success) { - new ActionTask(CancellationToken.None, () => { EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfAuthentications(); - }) { Affinity = TaskAffinity.UI }.Start(); Clear(); Finish(true); From d36f5ea8c64d2fdb7b9d1a97b44d3a3171c515b3 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 31 Jan 2018 09:19:13 -0500 Subject: [PATCH 0104/1008] Using the Manager member variable --- .../Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs | 2 +- .../Assets/Editor/GitHub.Unity/UI/BranchesView.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs index 8362ccfd0..9061ab05d 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs @@ -214,7 +214,7 @@ private void DoResult(bool success, string msg) if (success) { - EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfAuthentications(); + Manager.UsageTracker.IncrementNumberOfAuthentications(); Clear(); Finish(true); diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs index a8328629b..e278e6d22 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs @@ -272,7 +272,7 @@ private void OnButtonBarGUI() { if (success) { - EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfLocalBranchCreations(); + Manager.UsageTracker.IncrementNumberOfLocalBranchCreations(); Redraw(); } else @@ -440,7 +440,7 @@ private void CheckoutRemoteBranch(string branch) GitClient.CreateBranch(branchName, branch).FinallyInUI((success, e) => { if (success) { - EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfRemoteBranchCheckouts(); + Manager.UsageTracker.IncrementNumberOfRemoteBranchCheckouts(); Redraw(); } else @@ -461,7 +461,7 @@ private void SwitchBranch(string branch) GitClient.SwitchBranch(branch).FinallyInUI((success, e) => { if (success) { - EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfLocalBranchCheckouts(); + Manager.UsageTracker.IncrementNumberOfLocalBranchCheckouts(); Redraw(); } else @@ -480,7 +480,7 @@ private void DeleteLocalBranch(string branch) { GitClient .DeleteBranch(branch, true) - .ThenInUI(EntryPoint.ApplicationManager.UsageTracker.IncrementNumberOfLocalBranchDeletions) + .ThenInUI(Manager.UsageTracker.IncrementNumberOfLocalBranchDeletions) .Start(); } } From e6166caf73607e698f010e12ae991d80bf11e71e Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 31 Jan 2018 16:43:04 +0100 Subject: [PATCH 0105/1008] Set rulesets and code analysis and suppress some special cases --- common/build.targets | 7 +++-- ...all.ruleset => codeanalysis-debug.ruleset} | 12 +++++++++ ...l.ruleset => codeanalysis-release.ruleset} | 15 +++++++++++ common/properties.props | 11 ++++++++ src/GitHub.Api/GitHub.Api.csproj | 16 +++-------- src/GitHub.Api/GlobalSuppressions.cs | Bin 0 -> 2406 bytes src/GitHub.Logging/GitHub.Logging.csproj | 25 +++++------------- src/GitHub.Logging/GlobalSuppressions.cs | Bin 0 -> 1776 bytes .../Editor/GitHub.Unity/GitHub.Unity.csproj | 9 +++---- 9 files changed, 57 insertions(+), 38 deletions(-) rename common/{codeanalysis-small.ruleset => codeanalysis-debug.ruleset} (90%) rename common/{codeanalysis-full.ruleset => codeanalysis-release.ruleset} (88%) create mode 100644 src/GitHub.Api/GlobalSuppressions.cs create mode 100644 src/GitHub.Logging/GlobalSuppressions.cs diff --git a/common/build.targets b/common/build.targets index c80db3b01..ca88d77e4 100644 --- a/common/build.targets +++ b/common/build.targets @@ -5,8 +5,11 @@ Properties\SolutionInfo.cs - - Properties\GitHub.ruleset + + Properties\codeanalysis-release.ruleset + + + Properties\codeanalysis-debug.ruleset diff --git a/common/codeanalysis-small.ruleset b/common/codeanalysis-debug.ruleset similarity index 90% rename from common/codeanalysis-small.ruleset rename to common/codeanalysis-debug.ruleset index b380093ab..e2c4aed12 100644 --- a/common/codeanalysis-small.ruleset +++ b/common/codeanalysis-debug.ruleset @@ -94,6 +94,18 @@ + + + + + + + + + + + + diff --git a/common/codeanalysis-full.ruleset b/common/codeanalysis-release.ruleset similarity index 88% rename from common/codeanalysis-full.ruleset rename to common/codeanalysis-release.ruleset index 0985eed76..a0f070e85 100644 --- a/common/codeanalysis-full.ruleset +++ b/common/codeanalysis-release.ruleset @@ -80,6 +80,21 @@ + + + + + + + + + + + + + + + diff --git a/common/properties.props b/common/properties.props index 9d7fd40c6..6d47fe350 100644 --- a/common/properties.props +++ b/common/properties.props @@ -12,4 +12,15 @@ \Applications\Unity\Unity.app\Contents\Managed\ Debug + + + $(SolutionDir)\common\codeanalysis-debug.ruleset + + + $(SolutionDir)\common\codeanalysis-release.ruleset + + + $(SolutionDir)\common\codeanalysis-debug.ruleset + + \ No newline at end of file diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index b6c27a167..e9ece42ef 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -17,6 +17,9 @@ ..\UnityExtension\Assets\Editor\build\ + true + false + true @@ -26,10 +29,6 @@ DEBUG;TRACE prompt 4 - true - $(SolutionDir)\common\codeanalysis-full.ruleset - false - true pdbonly @@ -37,10 +36,6 @@ TRACE prompt 4 - true - $(SolutionDir)\common\codeanalysis-small.ruleset - false - true Release @@ -50,10 +45,6 @@ TRACE;DEBUG;DEVELOPER_BUILD prompt 4 - true - $(SolutionDir)\common\codeanalysis-small.ruleset - false - true Debug @@ -109,6 +100,7 @@ + diff --git a/src/GitHub.Api/GlobalSuppressions.cs b/src/GitHub.Api/GlobalSuppressions.cs new file mode 100644 index 0000000000000000000000000000000000000000..84ac2b9d0bdcb17a17f8208dbdc66f7d9362832e GIT binary patch literal 2406 zcmd6pUuzRl5XI+N@H;H=rG+-Fh@yfI#cHk8R!obC_>gYaG}>lEc2gQZy!tycz3!$d z0YRYzvU~5$ojG&n&)r`?KU?1_euZ7wsh!*0o?B);o|VNnP*~}*VrbuP|-Stye3R|-dJF+r$i=}^yM_m8W+QWKnZ;0;{#3y*tdd|CI4DVv6=XNfU=Dc<7funhgMDe`GZg`*i z=|eop|Jn`a+wrV}YTdrreYTw%J#7!Mhj%hOpdIe!VWmA>@}MID~E?<-#c!s@z z@GaXSl4EL3oM$jKVk&A{#d^lB>}AZMIsa)EXG_yK17nGX=A`mlUq8juswtiMqzN4A ziI{Dt9)_%y6wD z(mrqMAkA{w>3i-~le!~hSMQRhn?`Hh8+nV329ItqVIH_gS-+i&t;FO+UkW4MusLfIaFhq3bMFTz2EjAo@2k z+{W6V==cO#uHLAM%wFSFoziJBn%O7N%s@48MpYlW({X5FJIhh?QCX>?6VK6K PV|?gqMBhGitHub.Logging v3.5 512 + ..\UnityExtension\Assets\Editor\build\ + true + false + true + AnyCPU true full false - bin\Debug\ DEBUG;TRACE prompt - 4 - true - $(SolutionDir)\common\codeanalysis-full.ruleset AnyCPU pdbonly true - bin\Release\ TRACE prompt 4 - true - $(SolutionDir)\common\codeanalysis-small.ruleset - Release - - - AnyCPU true full false - bin\Debug\ DEBUG;TRACE;DEVELOPER_BUILD prompt - 4 - true - $(SolutionDir)\common\codeanalysis-small.ruleset Debug @@ -65,15 +55,13 @@ + - - Properties\SolutionInfo.cs - @@ -84,4 +72,5 @@ --> + \ No newline at end of file diff --git a/src/GitHub.Logging/GlobalSuppressions.cs b/src/GitHub.Logging/GlobalSuppressions.cs new file mode 100644 index 0000000000000000000000000000000000000000..b4be5af6339bf87a55bc2382659146d8dfbb242c GIT binary patch literal 1776 zcmdUwL5mYX5QXb3_#c|_k_9)r3!VfItKups2#JS91ZO8P8BH=_GFixbhN?G5t@ zHrMQwes+VUc1E_fHBZZ~ynot{@-nr76|Bfh>mD2XK`h0Qb?uP~dk&6*7}s`Xm;A0k zrid%IQQX!(@6p$+&g`|%rZxus+I?MPE1QdZ-n(ui3h`$+6;2GL8yYZ8GU492g>}IrQL_D)^_SBx(|5BAp zdqGu{5;!}QOATzsNVOmqw3|nPwVq9tMeV54XDGR78iCw<;Ub9 zZ6~x^lg*U3m~UB~l2JkpJN|Q5q?5i#@X}zhL{m~ow;$DSkM&D(O$3gTQyo0kMBDPF zj*;IvzNAoTUD!(RzXf)IEh5VQwpF{nGDu&4sV(v2nmN_B=}BDTcg1%telWU^?qX{#Cab>~wZc z995^XU#tgnfk*dc+>=t6SjoEwG>>U4?p$?ThbKi{gFW<512 $(SolutionDir)\unity\TestProject\Assets\Plugins\GitHub\Editor\ ..\..\..\obj\ + true + false + true @@ -22,8 +25,6 @@ DEBUG;TRACE prompt 4 - true - $(SolutionDir)\common\codeanalysis-full.ruleset 4 @@ -32,8 +33,6 @@ TRACE prompt 4 - true - $(SolutionDir)\common\codeanalysis-small.ruleset Release @@ -43,8 +42,6 @@ DEBUG;TRACE;DEVELOPER_BUILD prompt 4 - true - $(SolutionDir)\common\codeanalysis-small.ruleset 4 From 2a7643c4a1a51b9bafb43b4d4fd52d5f817f650c Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 31 Jan 2018 16:45:40 +0100 Subject: [PATCH 0106/1008] Add default exception constructors --- src/GitHub.Api/Application/ApiClient.cs | 16 ++++++++++++- src/GitHub.Api/Helpers/Guard.cs | 4 ++++ src/GitHub.Api/Helpers/TaskHelpers.cs | 9 ++++++++ .../Tasks/TaskCanceledExceptions.cs | 23 +++++++++++++++++-- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/GitHub.Api/Application/ApiClient.cs b/src/GitHub.Api/Application/ApiClient.cs index a02db0bc4..13c082051 100644 --- a/src/GitHub.Api/Application/ApiClient.cs +++ b/src/GitHub.Api/Application/ApiClient.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Octokit; +using System.Runtime.Serialization; namespace GitHub.Unity { @@ -333,7 +334,7 @@ class GitHubRepository } [Serializable] - class ApiClientException : Exception + public class ApiClientException : Exception { public ApiClientException() { } @@ -343,6 +344,9 @@ public ApiClientException(string message) : base(message) public ApiClientException(string message, Exception innerException) : base(message, innerException) { } + + protected ApiClientException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } [Serializable] @@ -356,6 +360,8 @@ public TokenUsernameMismatchException(string cachedUsername, string currentUsern CachedUsername = cachedUsername; CurrentUsername = currentUsername; } + protected TokenUsernameMismatchException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } [Serializable] @@ -363,5 +369,13 @@ class KeychainEmptyException : ApiClientException { public KeychainEmptyException() { } + public KeychainEmptyException(string message) : base(message) + { } + + public KeychainEmptyException(string message, Exception innerException) : base(message, innerException) + { } + + protected KeychainEmptyException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } } diff --git a/src/GitHub.Api/Helpers/Guard.cs b/src/GitHub.Api/Helpers/Guard.cs index ae75bfb50..053576773 100644 --- a/src/GitHub.Api/Helpers/Guard.cs +++ b/src/GitHub.Api/Helpers/Guard.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Runtime.Serialization; namespace GitHub.Unity { @@ -11,6 +12,9 @@ internal class InstanceNotInitializedException : InvalidOperationException public InstanceNotInitializedException(object the, string property) : base(String.Format(CultureInfo.InvariantCulture, "{0} is not correctly initialized, {1} is null", the?.GetType().Name, property)) {} + + protected InstanceNotInitializedException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } internal static class Guard diff --git a/src/GitHub.Api/Helpers/TaskHelpers.cs b/src/GitHub.Api/Helpers/TaskHelpers.cs index eaaafd4fa..33481c029 100644 --- a/src/GitHub.Api/Helpers/TaskHelpers.cs +++ b/src/GitHub.Api/Helpers/TaskHelpers.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.Serialization; using System.Threading.Tasks; namespace GitHub.Unity @@ -21,5 +22,13 @@ public static Task ToTask(this Exception exception) [Serializable] public class NotReadyException : Exception { + public NotReadyException() : base() + { } + public NotReadyException(string message) : base(message) + { } + public NotReadyException(string message, Exception innerException) : base(message, innerException) + { } + protected NotReadyException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } } \ No newline at end of file diff --git a/src/GitHub.Api/Tasks/TaskCanceledExceptions.cs b/src/GitHub.Api/Tasks/TaskCanceledExceptions.cs index cde037ce6..ee61e3ab8 100644 --- a/src/GitHub.Api/Tasks/TaskCanceledExceptions.cs +++ b/src/GitHub.Api/Tasks/TaskCanceledExceptions.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.Serialization; using System.Threading.Tasks; namespace GitHub.Unity @@ -6,14 +7,32 @@ namespace GitHub.Unity [Serializable] class DependentTaskFailedException : TaskCanceledException { - public DependentTaskFailedException(ITask task, Exception ex) : base(ex.InnerException != null ? ex.InnerException.Message : ex.Message, ex.InnerException ?? ex) + protected DependentTaskFailedException() : base() + { } + protected DependentTaskFailedException(string message) : base(message) + { } + protected DependentTaskFailedException(string message, Exception innerException) : base(message, innerException) + { } + protected DependentTaskFailedException(SerializationInfo info, StreamingContext context) : base(info, context) + { } + + public DependentTaskFailedException(ITask task, Exception ex) : this(ex.InnerException != null ? ex.InnerException.Message : ex.Message, ex.InnerException ?? ex) {} } [Serializable] class ProcessException : TaskCanceledException { - public ProcessException(ITask process) : base(process.Errors) + protected ProcessException() : base() + { } + protected ProcessException(string message) : base(message) + { } + protected ProcessException(string message, Exception innerException) : base(message, innerException) + { } + protected ProcessException(SerializationInfo info, StreamingContext context) : base(info, context) + { } + + public ProcessException(ITask process) : this(process.Errors) { } } } \ No newline at end of file From de373f29c5273c59533c049685ade26b1b64c0ab Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 31 Jan 2018 16:46:14 +0100 Subject: [PATCH 0107/1008] Make abstract class constructors protected --- src/GitHub.Api/Tasks/TaskBase.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index d54f24d76..113f758c6 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -70,7 +70,7 @@ public abstract class TaskBase : ITask protected event Func faultHandler; private event Action finallyHandler; - public TaskBase(CancellationToken token) + protected TaskBase(CancellationToken token) { Guard.ArgumentNotNull(token, "token"); @@ -78,7 +78,7 @@ public TaskBase(CancellationToken token) Task = new Task(() => Run(DependsOn?.Successful ?? previousSuccess), Token, TaskCreationOptions.None); } - public TaskBase(Task task) + protected TaskBase(Task task) { Task = new Task(t => { @@ -398,7 +398,7 @@ abstract class TaskBase : TaskBase, ITask public new event Action> OnStart; public new event Action, TResult> OnEnd; - public TaskBase(CancellationToken token) + protected TaskBase(CancellationToken token) : base(token) { Task = new Task(() => @@ -410,7 +410,7 @@ public TaskBase(CancellationToken token) }, Token, TaskCreationOptions.None); } - public TaskBase(Task task) + protected TaskBase(Task task) : base() { Task = new Task(t => From d9fde96c12fad52ea2c36d014422e43be37f3963 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 31 Jan 2018 16:50:23 +0100 Subject: [PATCH 0108/1008] String comparison fixes --- src/GitHub.Api/IO/NiceIO.cs | 4 ++-- src/GitHub.Api/Installer/GitInstaller.cs | 2 +- src/GitHub.Api/OutputProcessors/LogEntryOutputProcessor.cs | 2 +- .../OutputProcessors/RemoteListOutputProcessor.cs | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/GitHub.Api/IO/NiceIO.cs b/src/GitHub.Api/IO/NiceIO.cs index 775fdaab2..018105757 100644 --- a/src/GitHub.Api/IO/NiceIO.cs +++ b/src/GitHub.Api/IO/NiceIO.cs @@ -464,8 +464,8 @@ public int CompareTo(object obj) public bool HasExtension(params string[] extensions) { - var extensionWithDotLower = ExtensionWithDot.ToLower(CultureInfo.InvariantCulture); - return extensions.Any(e => WithDot(e).ToLower(CultureInfo.InvariantCulture) == extensionWithDotLower); + var extensionWithDotLower = ExtensionWithDot.ToUpperInvariant(); + return extensions.Any(e => WithDot(e).ToUpperInvariant() == extensionWithDotLower); } private static string WithDot(string extension) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index ef7640fef..5c84a6e6f 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -99,7 +99,7 @@ public bool IsGitLfsExtracted() var calculateMd5 = environment.FileSystem.CalculateMD5(GitLfsExecutablePath); logger.Trace("GitLFS MD5: {0}", calculateMd5); var md5 = environment.IsWindows ? WindowsGitLfsExecutableMD5 : MacGitLfsExecutableMD5; - if (md5.Equals(calculateMd5, StringComparison.InvariantCultureIgnoreCase)) + if (md5.Equals(calculateMd5, StringComparison.OrdinalIgnoreCase)) { logger.Trace("{0} has incorrect MD5", GitExecutablePath); return false; diff --git a/src/GitHub.Api/OutputProcessors/LogEntryOutputProcessor.cs b/src/GitHub.Api/OutputProcessors/LogEntryOutputProcessor.cs index 493f3760f..4ad7f6560 100644 --- a/src/GitHub.Api/OutputProcessors/LogEntryOutputProcessor.cs +++ b/src/GitHub.Api/OutputProcessors/LogEntryOutputProcessor.cs @@ -135,7 +135,7 @@ public override void LineReceived(string line) case ProcessingPhase.Summary: { - var idx = line.IndexOf("---GHUBODYEND---", StringComparison.InvariantCulture); + var idx = line.IndexOf("---GHUBODYEND---", StringComparison.Ordinal); var oneliner = idx >= 0; if (oneliner) { diff --git a/src/GitHub.Api/OutputProcessors/RemoteListOutputProcessor.cs b/src/GitHub.Api/OutputProcessors/RemoteListOutputProcessor.cs index 293ebf142..03f8f9d68 100644 --- a/src/GitHub.Api/OutputProcessors/RemoteListOutputProcessor.cs +++ b/src/GitHub.Api/OutputProcessors/RemoteListOutputProcessor.cs @@ -56,10 +56,10 @@ public override void LineReceived(string line) private void ReturnRemote() { - var modes = currentModes.Select(s => s.ToLowerInvariant()).ToArray(); + var modes = currentModes.Select(s => s.ToUpperInvariant()).ToArray(); - var isFetch = modes.Contains("fetch"); - var isPush = modes.Contains("push"); + var isFetch = modes.Contains("FETCH"); + var isPush = modes.Contains("PUSH"); GitRemoteFunction remoteFunction; if (isFetch && isPush) From da286caaef10866bc1c5788b10306e6bbbcce8f9 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 31 Jan 2018 16:51:08 +0100 Subject: [PATCH 0109/1008] Implementing equality ops in all structs to avoid the default reflection implementation --- src/GitHub.Api/Authentication/Keychain.cs | 42 ++++++++++ src/GitHub.Api/Extensions/StringExtensions.cs | 40 +++++++++ src/GitHub.Api/Git/GitAheadBehindStatus.cs | 39 +++++++++ src/GitHub.Api/Git/GitBranch.cs | 43 ++++++++++ src/GitHub.Api/Git/GitClient.cs | 42 ++++++++++ src/GitHub.Api/Git/GitConfig.cs | 84 +++++++++++++++++++ src/GitHub.Api/Git/GitLogEntry.cs | 62 ++++++++++++++ src/GitHub.Api/Git/GitRemote.cs | 51 +++++++++++ src/GitHub.Api/Git/GitStatus.cs | 48 +++++++++++ src/GitHub.Api/Git/GitStatusEntry.cs | 50 +++++++++++ src/GitHub.Api/Git/Repository.cs | 50 ++++++++++- src/GitHub.Api/Git/TreeData.cs | 79 +++++++++++++++++ .../Git/ValidateGitInstallResult.cs | 43 ++++++++++ src/GitHub.Api/IO/NiceIO.cs | 22 +++++ 14 files changed, 691 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/Authentication/Keychain.cs b/src/GitHub.Api/Authentication/Keychain.cs index bab311239..0a57913df 100644 --- a/src/GitHub.Api/Authentication/Keychain.cs +++ b/src/GitHub.Api/Authentication/Keychain.cs @@ -10,6 +10,48 @@ public struct Connection { public UriString Host; public string Username; + + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + (Host?.GetHashCode() ?? 0); + hash = hash * 23 + (Username?.GetHashCode() ?? 0); + return hash; + } + + public override bool Equals(object other) + { + if (other is Connection) + return Equals((Connection)other); + return false; + } + + public bool Equals(Connection other) + { + return + object.Equals(Host, other.Host) && + String.Equals(Username, other.Username) + ; + } + + public static bool operator ==(Connection lhs, Connection rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(Connection lhs, Connection rhs) + { + return !(lhs == rhs); + } } class ConnectionCacheItem diff --git a/src/GitHub.Api/Extensions/StringExtensions.cs b/src/GitHub.Api/Extensions/StringExtensions.cs index 3fbda676d..0f6eae53d 100644 --- a/src/GitHub.Api/Extensions/StringExtensions.cs +++ b/src/GitHub.Api/Extensions/StringExtensions.cs @@ -156,5 +156,45 @@ public struct StringResult public string Chunk; public int Start; public int End; + + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + (Chunk?.GetHashCode() ?? 0); + hash = hash * 23 + Start.GetHashCode(); + hash = hash * 23 + End.GetHashCode(); + return hash; + } + + public override bool Equals(object other) + { + if (other is StringResult) + return Equals((StringResult)other); + return false; + } + + public bool Equals(StringResult other) + { + return String.Equals(Chunk, other.Chunk) && Start == other.Start && End == other.End; + } + + public static bool operator ==(StringResult lhs, StringResult rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(StringResult lhs, StringResult rhs) + { + return !(lhs == rhs); + } } } diff --git a/src/GitHub.Api/Git/GitAheadBehindStatus.cs b/src/GitHub.Api/Git/GitAheadBehindStatus.cs index 2cb0ade1b..57163fcbc 100644 --- a/src/GitHub.Api/Git/GitAheadBehindStatus.cs +++ b/src/GitHub.Api/Git/GitAheadBehindStatus.cs @@ -16,6 +16,45 @@ public GitAheadBehindStatus(int ahead, int behind) this.behind = behind; } + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + ahead.GetHashCode(); + hash = hash * 23 + behind.GetHashCode(); + return hash; + } + + public override bool Equals(object other) + { + if (other is GitAheadBehindStatus) + return Equals((GitAheadBehindStatus)other); + return false; + } + + public bool Equals(GitAheadBehindStatus other) + { + return ahead == other.ahead && behind == other.behind; + } + + public static bool operator ==(GitAheadBehindStatus lhs, GitAheadBehindStatus rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(GitAheadBehindStatus lhs, GitAheadBehindStatus rhs) + { + return !(lhs == rhs); + } + public int Ahead => ahead; public int Behind => behind; diff --git a/src/GitHub.Api/Git/GitBranch.cs b/src/GitHub.Api/Git/GitBranch.cs index 21aad3e25..d6d38a4f2 100644 --- a/src/GitHub.Api/Git/GitBranch.cs +++ b/src/GitHub.Api/Git/GitBranch.cs @@ -20,6 +20,49 @@ public GitBranch(string name, string tracking, bool active) this.isActive = active; } + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + (name?.GetHashCode() ?? 0); + hash = hash * 23 + (tracking?.GetHashCode() ?? 0); + hash = hash * 23 + isActive.GetHashCode(); + return hash; + } + + public override bool Equals(object other) + { + if (other is GitBranch) + return Equals((GitBranch)other); + return false; + } + + public bool Equals(GitBranch other) + { + return + String.Equals(name, other.name) && + String.Equals(tracking, other.tracking) && + isActive == other.isActive; + } + + public static bool operator ==(GitBranch lhs, GitBranch rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(GitBranch lhs, GitBranch rhs) + { + return !(lhs == rhs); + } + public string Name => name; public string Tracking => tracking; public bool IsActive => isActive; diff --git a/src/GitHub.Api/Git/GitClient.cs b/src/GitHub.Api/Git/GitClient.cs index a013eb9ee..15301d16c 100644 --- a/src/GitHub.Api/Git/GitClient.cs +++ b/src/GitHub.Api/Git/GitClient.cs @@ -492,6 +492,48 @@ public GitUser(string name, string email) this.email = email; } + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + (name?.GetHashCode() ?? 0); + hash = hash * 23 + (email?.GetHashCode() ?? 0); + return hash; + } + + public override bool Equals(object other) + { + if (other is GitUser) + return Equals((GitUser)other); + return false; + } + + public bool Equals(GitUser other) + { + return + String.Equals(name, other.name) && + String.Equals(email, other.email) + ; + } + + public static bool operator ==(GitUser lhs, GitUser rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(GitUser lhs, GitUser rhs) + { + return !(lhs == rhs); + } + public override string ToString() { return $"Name:\"{Name}\" Email:\"{Email}\""; diff --git a/src/GitHub.Api/Git/GitConfig.cs b/src/GitHub.Api/Git/GitConfig.cs index 05bf63d35..dd0cc5f18 100644 --- a/src/GitHub.Api/Git/GitConfig.cs +++ b/src/GitHub.Api/Git/GitConfig.cs @@ -20,6 +20,48 @@ public ConfigRemote(string name, string url) this.url = url; } + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + (name?.GetHashCode() ?? 0); + hash = hash * 23 + (url?.GetHashCode() ?? 0); + return hash; + } + + public override bool Equals(object other) + { + if (other is ConfigRemote) + return Equals((ConfigRemote)other); + return false; + } + + public bool Equals(ConfigRemote other) + { + return + String.Equals(name, other.name) && + String.Equals(url, other.url) + ; + } + + public static bool operator ==(ConfigRemote lhs, ConfigRemote rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(ConfigRemote lhs, ConfigRemote rhs) + { + return !(lhs == rhs); + } + public string Name => name; public string Url => url; @@ -50,6 +92,48 @@ public ConfigBranch(string name, ConfigRemote? remote) this.remote = remote ?? ConfigRemote.Default; } + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + (name?.GetHashCode() ?? 0); + hash = hash * 23 + remote.GetHashCode(); + return hash; + } + + public override bool Equals(object other) + { + if (other is ConfigBranch) + return Equals((ConfigBranch)other); + return false; + } + + public bool Equals(ConfigBranch other) + { + return + String.Equals(name, other.name) && + remote.Equals(other.remote) + ; + } + + public static bool operator ==(ConfigBranch lhs, ConfigBranch rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(ConfigBranch lhs, ConfigBranch rhs) + { + return !(lhs == rhs); + } + public bool IsTracking => Remote.HasValue; public string Name => name; diff --git a/src/GitHub.Api/Git/GitLogEntry.cs b/src/GitHub.Api/Git/GitLogEntry.cs index 10b2fed11..a36b1fe73 100644 --- a/src/GitHub.Api/Git/GitLogEntry.cs +++ b/src/GitHub.Api/Git/GitLogEntry.cs @@ -128,6 +128,68 @@ private set } } + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + (commitID?.GetHashCode() ?? 0); + hash = hash * 23 + (mergeA?.GetHashCode() ?? 0); + hash = hash * 23 + (mergeB?.GetHashCode() ?? 0); + hash = hash * 23 + (authorName?.GetHashCode() ?? 0); + hash = hash * 23 + (authorEmail?.GetHashCode() ?? 0); + hash = hash * 23 + (commitEmail?.GetHashCode() ?? 0); + hash = hash * 23 + (commitName?.GetHashCode() ?? 0); + hash = hash * 23 + (summary?.GetHashCode() ?? 0); + hash = hash * 23 + (description?.GetHashCode() ?? 0); + hash = hash * 23 + (timeString?.GetHashCode() ?? 0); + hash = hash * 23 + (commitTimeString?.GetHashCode() ?? 0); + hash = hash * 23 + (changes?.GetHashCode() ?? 0); + return hash; + } + + public override bool Equals(object other) + { + if (other is GitLogEntry) + return Equals((GitLogEntry)other); + return false; + } + + public bool Equals(GitLogEntry other) + { + return + String.Equals(commitID, other.commitID) && + String.Equals(mergeA, other.mergeA) && + String.Equals(mergeB, other.mergeB) && + String.Equals(authorName, other.authorName) && + String.Equals(authorEmail, other.authorEmail) && + String.Equals(commitEmail, other.commitEmail) && + String.Equals(commitName, other.commitName) && + String.Equals(summary, other.summary) && + String.Equals(description, other.description) && + String.Equals(timeString, other.timeString) && + String.Equals(commitTimeString, other.commitTimeString) && + object.Equals(changes, other.changes) + ; + } + + public static bool operator ==(GitLogEntry lhs, GitLogEntry rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(GitLogEntry lhs, GitLogEntry rhs) + { + return !(lhs == rhs); + } + public string ShortID => CommitID.Length < 7 ? CommitID : CommitID.Substring(0, 7); public string CommitID => commitID; diff --git a/src/GitHub.Api/Git/GitRemote.cs b/src/GitHub.Api/Git/GitRemote.cs index 83db23d82..dc9c6e184 100644 --- a/src/GitHub.Api/Git/GitRemote.cs +++ b/src/GitHub.Api/Git/GitRemote.cs @@ -68,6 +68,57 @@ public GitRemote(string name, string url) this.function = GitRemoteFunction.Unknown; } + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + (name?.GetHashCode() ?? 0); + hash = hash * 23 + (url?.GetHashCode() ?? 0); + hash = hash * 23 + (login?.GetHashCode() ?? 0); + hash = hash * 23 + (user?.GetHashCode() ?? 0); + hash = hash * 23 + (host?.GetHashCode() ?? 0); + hash = hash * 23 + function.GetHashCode(); + hash = hash * 23 + (token?.GetHashCode() ?? 0); + return hash; + } + + public override bool Equals(object other) + { + if (other is GitRemote) + return Equals((GitRemote)other); + return false; + } + + public bool Equals(GitRemote other) + { + return + String.Equals(name, other.name) && + String.Equals(url, other.url) && + String.Equals(login, other.login) && + String.Equals(user, other.user) && + String.Equals(host, other.host) && + function == other.function && + String.Equals(token, other.token) + ; + } + + public static bool operator ==(GitRemote lhs, GitRemote rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(GitRemote lhs, GitRemote rhs) + { + return !(lhs == rhs); + } public override string ToString() { var sb = new StringBuilder(); diff --git a/src/GitHub.Api/Git/GitStatus.cs b/src/GitHub.Api/Git/GitStatus.cs index 7d9b66c47..02ab33f1d 100644 --- a/src/GitHub.Api/Git/GitStatus.cs +++ b/src/GitHub.Api/Git/GitStatus.cs @@ -12,6 +12,54 @@ public struct GitStatus public int Behind; public List Entries; + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + (LocalBranch?.GetHashCode() ?? 0); + hash = hash * 23 + (RemoteBranch?.GetHashCode() ?? 0); + hash = hash * 23 + Ahead.GetHashCode(); + hash = hash * 23 + Behind.GetHashCode(); + hash = hash * 23 + (Entries?.GetHashCode() ?? 0); + return hash; + } + + public override bool Equals(object other) + { + if (other is GitStatus) + return Equals((GitStatus)other); + return false; + } + + public bool Equals(GitStatus other) + { + return + String.Equals(LocalBranch, other.LocalBranch) && + String.Equals(RemoteBranch, other.RemoteBranch) && + Ahead == other.Ahead && + Behind == other.Behind && + object.Equals(Entries, other.Entries) + ; + } + + public static bool operator ==(GitStatus lhs, GitStatus rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(GitStatus lhs, GitStatus rhs) + { + return !(lhs == rhs); + } + public override string ToString() { var remoteBranchString = string.IsNullOrEmpty(RemoteBranch) ? "?" : string.Format("\"{0}\"", RemoteBranch); diff --git a/src/GitHub.Api/Git/GitStatusEntry.cs b/src/GitHub.Api/Git/GitStatusEntry.cs index ae07d3d6a..1421c5554 100644 --- a/src/GitHub.Api/Git/GitStatusEntry.cs +++ b/src/GitHub.Api/Git/GitStatusEntry.cs @@ -29,6 +29,56 @@ public GitStatusEntry(string path, string fullPath, string projectPath, this.staged = staged; } + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + (path?.GetHashCode() ?? 0); + hash = hash * 23 + (fullPath?.GetHashCode() ?? 0); + hash = hash * 23 + (projectPath?.GetHashCode() ?? 0); + hash = hash * 23 + (originalPath?.GetHashCode() ?? 0); + hash = hash * 23 + status.GetHashCode(); + hash = hash * 23 + staged.GetHashCode(); + return hash; + } + + public override bool Equals(object other) + { + if (other is GitStatusEntry) + return Equals((GitStatusEntry)other); + return false; + } + + public bool Equals(GitStatusEntry other) + { + return + String.Equals(path, other.path) && + String.Equals(fullPath, other.fullPath) && + String.Equals(projectPath, other.projectPath) && + String.Equals(originalPath, other.originalPath) && + status == other.status && + staged == other.staged + ; + } + + public static bool operator ==(GitStatusEntry lhs, GitStatusEntry rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(GitStatusEntry lhs, GitStatusEntry rhs) + { + return !(lhs == rhs); + } + public string Path => path; public string FullPath => fullPath; diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 8de636c76..efd4ae010 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -472,11 +472,11 @@ private void ClearRepositoryInfo() private GitBranch GetLocalGitBranch(ConfigBranch x) { - var name = x.Name; - var trackingName = x.IsTracking ? x.Remote.Value.Name + "/" + name : "[None]"; - var isActive = name == CurrentBranchName; + var branchName = x.Name; + var trackingName = x.IsTracking ? x.Remote.Value.Name + "/" + branchName : "[None]"; + var isActive = branchName == CurrentBranchName; - return new GitBranch(name, trackingName, isActive); + return new GitBranch(branchName, trackingName, isActive); } private static GitBranch GetRemoteGitBranch(ConfigBranch x) @@ -759,6 +759,48 @@ public struct CacheUpdateEvent [NonSerialized] private DateTimeOffset? updatedTimeValue; public string updatedTimeString; + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + updatedTimeValue.GetHashCode(); + hash = hash * 23 + (updatedTimeString?.GetHashCode() ?? 0); + return hash; + } + + public override bool Equals(object other) + { + if (other is CacheUpdateEvent) + return Equals((CacheUpdateEvent)other); + return false; + } + + public bool Equals(CacheUpdateEvent other) + { + return + object.Equals(updatedTimeValue, other.updatedTimeValue) && + String.Equals(updatedTimeString, other.updatedTimeString) + ; + } + + public static bool operator ==(CacheUpdateEvent lhs, CacheUpdateEvent rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(CacheUpdateEvent lhs, CacheUpdateEvent rhs) + { + return !(lhs == rhs); + } + public DateTimeOffset UpdatedTime { get diff --git a/src/GitHub.Api/Git/TreeData.cs b/src/GitHub.Api/Git/TreeData.cs index 4e8707925..1f5141fb3 100644 --- a/src/GitHub.Api/Git/TreeData.cs +++ b/src/GitHub.Api/Git/TreeData.cs @@ -20,6 +20,44 @@ public GitBranchTreeData(GitBranch gitBranch) GitBranch = gitBranch; } + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + GitBranch.GetHashCode(); + return hash; + } + + public override bool Equals(object other) + { + if (other is GitBranchTreeData) + return Equals((GitBranchTreeData)other); + return false; + } + + public bool Equals(GitBranchTreeData other) + { + return GitBranch.Equals(other.GitBranch); + } + + public static bool operator ==(GitBranchTreeData lhs, GitBranchTreeData rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(GitBranchTreeData lhs, GitBranchTreeData rhs) + { + return !(lhs == rhs); + } + public string Path => GitBranch.Name; public bool IsActive => GitBranch.IsActive; } @@ -38,6 +76,47 @@ public GitStatusEntryTreeData(GitStatusEntry gitStatusEntry, bool isLocked = fal this.gitStatusEntry = gitStatusEntry; } + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + gitStatusEntry.GetHashCode(); + hash = hash * 23 + isLocked.GetHashCode(); + return hash; + } + + public override bool Equals(object other) + { + if (other is GitStatusEntryTreeData) + return Equals((GitStatusEntryTreeData)other); + return false; + } + + public bool Equals(GitStatusEntryTreeData other) + { + return + gitStatusEntry.Equals(other.gitStatusEntry) && + isLocked == other.isLocked; + } + + public static bool operator ==(GitStatusEntryTreeData lhs, GitStatusEntryTreeData rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(GitStatusEntryTreeData lhs, GitStatusEntryTreeData rhs) + { + return !(lhs == rhs); + } + public string Path => gitStatusEntry.Path; public string ProjectPath => gitStatusEntry.ProjectPath; public bool IsActive => false; diff --git a/src/GitHub.Api/Git/ValidateGitInstallResult.cs b/src/GitHub.Api/Git/ValidateGitInstallResult.cs index d978f3961..978931eb3 100644 --- a/src/GitHub.Api/Git/ValidateGitInstallResult.cs +++ b/src/GitHub.Api/Git/ValidateGitInstallResult.cs @@ -14,5 +14,48 @@ public ValidateGitInstallResult(bool isValid, Version gitVersion, Version gitLfs GitVersion = gitVersion; GitLfsVersion = gitLfsVersion; } + + public override int GetHashCode() + { + int hash = 17; + hash = hash * 23 + IsValid.GetHashCode(); + hash = hash * 23 + (GitVersion?.GetHashCode() ?? 0); + hash = hash * 23 + (GitLfsVersion?.GetHashCode() ?? 0); + return hash; + } + + public override bool Equals(object other) + { + if (other is ValidateGitInstallResult) + return Equals((ValidateGitInstallResult)other); + return false; + } + + public bool Equals(ValidateGitInstallResult other) + { + return IsValid == other.IsValid && + object.Equals(GitVersion, other.GitVersion) && + object.Equals(GitLfsVersion, other.GitLfsVersion) + ; + } + + public static bool operator ==(ValidateGitInstallResult lhs, ValidateGitInstallResult rhs) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(lhs, rhs)) + return true; + + // If one is null, but not both, return false. + if (((object)lhs == null) || ((object)rhs == null)) + return false; + + // Return true if the fields match: + return lhs.Equals(rhs); + } + + public static bool operator !=(ValidateGitInstallResult lhs, ValidateGitInstallResult rhs) + { + return !(lhs == rhs); + } } } \ No newline at end of file diff --git a/src/GitHub.Api/IO/NiceIO.cs b/src/GitHub.Api/IO/NiceIO.cs index 018105757..b938e393a 100644 --- a/src/GitHub.Api/IO/NiceIO.cs +++ b/src/GitHub.Api/IO/NiceIO.cs @@ -457,6 +457,28 @@ public int CompareTo(object obj) return this.ToString().CompareTo(((NPath)obj).ToString()); } + public static bool operator <(NPath lhs, NPath rhs) + { + return (Compare(lhs, rhs) < 0); + } + public static bool operator >(NPath lhs, NPath rhs) + { + return (Compare(lhs, rhs) > 0); + } + + public static int Compare(NPath lhs, NPath rhs) + { + if (object.ReferenceEquals(lhs, rhs)) + { + return 0; + } + if (object.ReferenceEquals(lhs, null)) + { + return -1; + } + return lhs.CompareTo(rhs); + } + public static bool operator !=(NPath a, NPath b) { return !(a == b); From df58256e262c4ecce84cad38246a6b4aad7ebc90 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 31 Jan 2018 17:07:40 +0100 Subject: [PATCH 0110/1008] Some more code analysis fixes --- common/codeanalysis-debug.ruleset | 5 +++++ common/codeanalysis-release.ruleset | 4 ++++ .../Editor/GitHub.Unity/ApplicationCache.cs | 18 ++++++++++++++++-- .../Editor/GitHub.Unity/ApplicationManager.cs | 2 +- .../GitHub.Unity/ScriptObjectSingleton.cs | 10 +++++----- .../GitHub.Unity/SerializableDictionary.cs | 2 +- .../Assets/Editor/GitHub.Unity/UI/Window.cs | 2 +- 7 files changed, 33 insertions(+), 10 deletions(-) diff --git a/common/codeanalysis-debug.ruleset b/common/codeanalysis-debug.ruleset index e2c4aed12..84a5625e4 100644 --- a/common/codeanalysis-debug.ruleset +++ b/common/codeanalysis-debug.ruleset @@ -106,6 +106,11 @@ + + + + + diff --git a/common/codeanalysis-release.ruleset b/common/codeanalysis-release.ruleset index a0f070e85..691d9a0f6 100644 --- a/common/codeanalysis-release.ruleset +++ b/common/codeanalysis-release.ruleset @@ -95,6 +95,10 @@ + + + + diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs index f34619cde..9337db871 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs @@ -2,12 +2,26 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Runtime.Serialization; using UnityEditor; using UnityEngine; using Application = UnityEngine.Application; namespace GitHub.Unity { + [Serializable] + public class SerializationException : Exception + { + public SerializationException() : base() + { } + public SerializationException(string message) : base(message) + { } + public SerializationException(string message, Exception innerException) : base(message, innerException) + { } + protected SerializationException(SerializationInfo info, StreamingContext context) : base(info, context) + { } + } + sealed class ApplicationCache : ScriptObjectSingleton { [SerializeField] private bool firstRun = true; @@ -373,7 +387,7 @@ public void OnAfterDeserialize() if (keys.Length != subKeys.Length || subKeys.Length != subKeyValues.Length) { - throw new Exception("Deserialization length mismatch"); + throw new SerializationException("Deserialization length mismatch"); } for (var remoteIndex = 0; remoteIndex < keys.Length; remoteIndex++) @@ -385,7 +399,7 @@ public void OnAfterDeserialize() if (subKeyContainer.Values.Length != subKeyValueContainer.Values.Length) { - throw new Exception("Deserialization length mismatch"); + throw new SerializationException("Deserialization length mismatch"); } var branchesDictionary = new Dictionary(); diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs index cb3a46c6a..c5fcfd00c 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs @@ -86,12 +86,12 @@ protected override void Dispose(bool disposing) { if (disposing) { - base.Dispose(disposing); if (!disposed) { disposed = true; } } + base.Dispose(disposing); } public override IProcessEnvironment GitEnvironment { get { return Platform.GitEnvironment; } } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs index 32f5f7042..8c6e7b6a3 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs @@ -6,7 +6,7 @@ namespace GitHub.Unity { [AttributeUsage(AttributeTargets.Class)] - class LocationAttribute : Attribute + sealed class LocationAttribute : Attribute { public enum Location { PreferencesFolder, ProjectFolder, LibraryFolder, UserFolder } public string filepath { get; set; } @@ -102,11 +102,11 @@ protected virtual void Save(bool saveAsText) return; } - NPath filePath = GetFilePath(); - if (filePath != null) + NPath locationFilePath = GetFilePath(); + if (locationFilePath != null) { - filePath.Parent.EnsureDirectoryExists(); - InternalEditorUtility.SaveToSerializedFileAndForget(new[] { instance }, filePath, saveAsText); + locationFilePath.Parent.EnsureDirectoryExists(); + InternalEditorUtility.SaveToSerializedFileAndForget(new[] { instance }, locationFilePath, saveAsText); } } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/SerializableDictionary.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/SerializableDictionary.cs index 0efc80e8b..4da39e12e 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/SerializableDictionary.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/SerializableDictionary.cs @@ -31,7 +31,7 @@ public void OnAfterDeserialize() if (keys.Count != values.Count) { - throw new Exception( + throw new SerializationException( string.Format("there are {0} keys and {1} values after deserialization. Make sure that both key and value types are serializable.", keys.Count, values.Count)); } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs index 54afa6a1e..746a31cfe 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs @@ -453,7 +453,7 @@ private Subview ToView(SubTab tab) case SubTab.Settings: return settingsView; default: - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException("tab"); } } From 154a687d1e162f3aadfe95a1aa0611a3149f7d8b Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 31 Jan 2018 17:13:38 +0100 Subject: [PATCH 0111/1008] Disable code analysis in the dev configuration, it's sloooow --- common/codeanalysis-debug.ruleset | 3 +++ common/codeanalysis-release.ruleset | 3 +++ src/GitHub.Api/GitHub.Api.csproj | 12 +++++++++--- src/GitHub.Logging/GitHub.Logging.csproj | 12 +++++++++--- .../Assets/Editor/GitHub.Unity/GitHub.Unity.csproj | 13 ++++++++++--- 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/common/codeanalysis-debug.ruleset b/common/codeanalysis-debug.ruleset index 84a5625e4..a14eb45ce 100644 --- a/common/codeanalysis-debug.ruleset +++ b/common/codeanalysis-debug.ruleset @@ -111,6 +111,9 @@ + + + diff --git a/common/codeanalysis-release.ruleset b/common/codeanalysis-release.ruleset index 691d9a0f6..c93efbfa4 100644 --- a/common/codeanalysis-release.ruleset +++ b/common/codeanalysis-release.ruleset @@ -99,6 +99,9 @@ + + + diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index e9ece42ef..22918ff24 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -17,9 +17,6 @@ ..\UnityExtension\Assets\Editor\build\ - true - false - true @@ -29,6 +26,9 @@ DEBUG;TRACE prompt 4 + true + false + true pdbonly @@ -37,6 +37,9 @@ prompt 4 Release + true + false + true true @@ -45,6 +48,9 @@ TRACE;DEBUG;DEVELOPER_BUILD prompt 4 + false + false + true Debug diff --git a/src/GitHub.Logging/GitHub.Logging.csproj b/src/GitHub.Logging/GitHub.Logging.csproj index 2f421d5dc..c18a2145d 100644 --- a/src/GitHub.Logging/GitHub.Logging.csproj +++ b/src/GitHub.Logging/GitHub.Logging.csproj @@ -12,9 +12,6 @@ v3.5 512 ..\UnityExtension\Assets\Editor\build\ - true - false - true @@ -24,6 +21,9 @@ false DEBUG;TRACE prompt + true + false + true AnyCPU @@ -32,6 +32,9 @@ TRACE prompt 4 + true + false + true AnyCPU @@ -40,6 +43,9 @@ false DEBUG;TRACE;DEVELOPER_BUILD prompt + false + false + true Debug diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj index e1b3413c3..1bc293176 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj @@ -13,9 +13,6 @@ 512 $(SolutionDir)\unity\TestProject\Assets\Plugins\GitHub\Editor\ ..\..\..\obj\ - true - false - true @@ -26,6 +23,9 @@ prompt 4 4 + true + false + true pdbonly @@ -33,7 +33,11 @@ TRACE prompt 4 + 4 Release + true + false + true true @@ -43,6 +47,9 @@ prompt 4 4 + false + false + true From e8461298987b67c1c4dc14e50d4381caa106fec3 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 25 Jan 2018 18:50:09 +0100 Subject: [PATCH 0112/1008] Can't help it, there's a typo, I see it --- src/tests/IntegrationTests/Download/DownloadTaskTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index dc37ce020..2d400aef1 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -93,7 +93,7 @@ public void TestDownloadTextTask() } [Test] - public void TestDownloadTextFailture() + public void TestDownloadTextFailure() { InitializeTaskManager(); From 7cf671b281175aa2712a17297129a6de8fc12b2a Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 29 Jan 2018 17:24:08 +0100 Subject: [PATCH 0113/1008] Use correct token for task cancellation to work --- src/GitHub.Api/Git/Repository.cs | 14 +++++++------- src/GitHub.Api/Git/RepositoryManager.cs | 2 +- .../IntegrationTests/BaseGitEnvironmentTest.cs | 2 +- .../BasePlatformIntegrationTest.cs | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 8de636c76..19c17ad13 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -382,7 +382,7 @@ private void HandleBranchCacheUpdatedEvent(CacheUpdateEvent cacheUpdateEvent) private void RepositoryManagerOnCurrentBranchUpdated(ConfigBranch? branch, ConfigRemote? remote) { - new ActionTask(CancellationToken.None, () => { + new ActionTask(TaskManager.Instance.Token, () => { if (!Nullable.Equals(CurrentConfigBranch, branch)) { var currentBranch = branch != null ? (GitBranch?)GetLocalGitBranch(branch.Value) : null; @@ -403,7 +403,7 @@ private void RepositoryManagerOnCurrentBranchUpdated(ConfigBranch? branch, Confi private void RepositoryManagerOnGitStatusUpdated(GitStatus gitStatus) { - new ActionTask(CancellationToken.None, () => { + new ActionTask(TaskManager.Instance.Token, () => { CurrentChanges = gitStatus.Entries; CurrentAhead = gitStatus.Ahead; CurrentBehind = gitStatus.Behind; @@ -412,7 +412,7 @@ private void RepositoryManagerOnGitStatusUpdated(GitStatus gitStatus) private void RepositoryManagerOnGitAheadBehindStatusUpdated(GitAheadBehindStatus aheadBehindStatus) { - new ActionTask(CancellationToken.None, () => { + new ActionTask(TaskManager.Instance.Token, () => { CurrentAhead = aheadBehindStatus.Ahead; CurrentBehind = aheadBehindStatus.Behind; }) { Affinity = TaskAffinity.UI }.Start(); @@ -420,14 +420,14 @@ private void RepositoryManagerOnGitAheadBehindStatusUpdated(GitAheadBehindStatus private void RepositoryManagerOnGitLogUpdated(List gitLogEntries) { - new ActionTask(CancellationToken.None, () => { + new ActionTask(TaskManager.Instance.Token, () => { CurrentLog = gitLogEntries; }) { Affinity = TaskAffinity.UI }.Start(); } private void RepositoryManagerOnGitLocksUpdated(List gitLocks) { - new ActionTask(CancellationToken.None, () => { + new ActionTask(TaskManager.Instance.Token, () => { CurrentLocks = gitLocks; }) { Affinity = TaskAffinity.UI }.Start(); @@ -436,7 +436,7 @@ private void RepositoryManagerOnGitLocksUpdated(List gitLocks) private void RepositoryManagerOnRemoteBranchesUpdated(Dictionary remotes, Dictionary> branches) { - new ActionTask(CancellationToken.None, () => { + new ActionTask(TaskManager.Instance.Token, () => { cacheContainer.BranchCache.SetRemotes(remotes, branches); Remotes = ConfigRemotes.Values.Select(GetGitRemote).ToArray(); RemoteBranches = RemoteConfigBranches.Values.SelectMany(x => x.Values).Select(GetRemoteGitBranch).ToArray(); @@ -445,7 +445,7 @@ private void RepositoryManagerOnRemoteBranchesUpdated(Dictionary branches) { - new ActionTask(CancellationToken.None, () => { + new ActionTask(TaskManager.Instance.Token, () => { cacheContainer.BranchCache.SetLocals(branches); UpdateLocalBranches(); }) { Affinity = TaskAffinity.UI }.Start(); diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index 70edbe8cd..f23f8507f 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -327,7 +327,7 @@ public void UpdateLocks() private ITask HookupHandlers(ITask task, bool isExclusive, bool filesystemChangesExpected) { - return new ActionTask(CancellationToken.None, () => { + return new ActionTask(TaskManager.Instance.Token, () => { if (isExclusive) { Logger.Trace("Starting Operation - Setting Busy Flag"); diff --git a/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs b/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs index 376c6bde1..522bdef8e 100644 --- a/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs +++ b/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs @@ -56,7 +56,7 @@ public override void OnSetup() TestRepoMasterTwoRemotes = TestBasePath.Combine("IOTestsRepo", "IOTestsRepo_master_two_remotes"); Logger.Trace("Extracting Zip File to {0}", TestBasePath); - ZipHelper.ExtractZipFile(TestZipFilePath, TestBasePath.ToString(), CancellationToken.None); + ZipHelper.ExtractZipFile(TestZipFilePath, TestBasePath.ToString(), TaskManager.Token); Logger.Trace("Extracted Zip File"); } diff --git a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs index e23264148..17df8feac 100644 --- a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs +++ b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs @@ -40,16 +40,16 @@ protected void InitializePlatform(NPath repoPath, NPath environmentPath, bool en var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); - var gitInstaller = new GitInstaller(Environment, CancellationToken.None, installDetails, gitArchivePath, gitLfsArchivePath); + var gitInstaller = new GitInstaller(Environment, TaskManager.Token, installDetails, gitArchivePath, gitLfsArchivePath); NPath result = null; Exception ex = null; - gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken.None, (b, path) => { + gitInstaller.SetupGitIfNeeded(new ActionTask(TaskManager.Token, (b, path) => { result = path; autoResetEvent.Set(); }), - new ActionTask(CancellationToken.None, (b, exception) => { + new ActionTask(TaskManager.Token, (b, exception) => { ex = exception; autoResetEvent.Set(); })); From c48a2b3a8d62d56ea20fc09d9b346a71662edbf6 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 29 Jan 2018 17:24:47 +0100 Subject: [PATCH 0114/1008] Make DownloadTask cancellable and add progress reporting --- src/GitHub.Api/GitHub.Api.csproj | 2 +- src/GitHub.Api/Helpers/Progress.cs | 35 +++ src/GitHub.Api/Helpers/ProgressReport.cs | 10 - src/GitHub.Api/Installer/GitInstaller.cs | 54 ++-- src/GitHub.Api/Primitives/UriString.cs | 10 +- src/GitHub.Api/Tasks/DownloadTask.cs | 287 +++++++++--------- src/GitHub.Api/Tasks/TaskBase.cs | 49 ++- .../IntegrationTests/BaseIntegrationTest.cs | 17 ++ .../BasePlatformIntegrationTest.cs | 6 +- .../IntegrationTests/BaseTaskManagerTest.cs | 6 + .../Download/DownloadTaskTests.cs | 105 +++++-- .../IntegrationTestEnvironment.cs | 12 +- 12 files changed, 383 insertions(+), 210 deletions(-) create mode 100644 src/GitHub.Api/Helpers/Progress.cs delete mode 100644 src/GitHub.Api/Helpers/ProgressReport.cs diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 894606c62..6c6aa80ef 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -149,7 +149,7 @@ - + diff --git a/src/GitHub.Api/Helpers/Progress.cs b/src/GitHub.Api/Helpers/Progress.cs new file mode 100644 index 000000000..7aadf605f --- /dev/null +++ b/src/GitHub.Api/Helpers/Progress.cs @@ -0,0 +1,35 @@ +using System; + +namespace GitHub.Unity +{ + public interface IProgress + { + ITask Task { get; } + /// + /// From 0 to 1 + /// + float Percentage { get; } + long Value { get; } + long Total { get; } + } + + public class Progress : IProgress + { + public ITask Task { get; internal set; } + public float Percentage { get { return Total > 0 ? (float)(double)Value / Total : 0f; } } + public long Value { get; internal set; } + public long Total { get; internal set; } + + private long previousValue; + private float averageSpeed = -1f; + private float lastSpeed = 0f; + private float smoothing = 0.005f; + + public void UpdateProgress(long value, long total) + { + previousValue = Value; + Total = total; + Value = value; + } + } +} diff --git a/src/GitHub.Api/Helpers/ProgressReport.cs b/src/GitHub.Api/Helpers/ProgressReport.cs deleted file mode 100644 index 571c3a592..000000000 --- a/src/GitHub.Api/Helpers/ProgressReport.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Rackspace.Threading; - -namespace GitHub.Unity -{ - class ProgressReport - { - public Progress Percentage = new Progress(); - public Progress Remaining = new Progress(); - } -} \ No newline at end of file diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 55ef123ce..58f308c0e 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -175,30 +175,36 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) private ITask CreateDownloadTask() { var tempZipPath = NPath.CreateTempDirectory("git_zip_paths"); - gitArchiveFilePath = tempZipPath.Combine("git.zip"); - gitLfsArchivePath = tempZipPath.Combine("git-lfs.zip"); - - var downloadGitMd5Task = new DownloadTextTask(CancellationToken.None, - "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt"); - - var downloadGitTask = new DownloadTask(CancellationToken.None, environment.FileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git.zip", gitArchiveFilePath, retryCount: 1); - - var downloadGitLfsMd5Task = new DownloadTextTask(CancellationToken.None, - "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt"); - - var downloadGitLfsTask = new DownloadTask(CancellationToken.None, environment.FileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip", gitLfsArchivePath, retryCount: 1); - - return downloadGitMd5Task.Then((b, s) => { - downloadGitTask.ValidationHash = s; - }) - .Then(downloadGitTask) - .Then(downloadGitLfsMd5Task) - .Then((b, s) => { - downloadGitLfsTask.ValidationHash = s; - }) - .Then(downloadGitLfsTask); + gitArchiveFilePath = tempZipPath.Combine("git"); + gitLfsArchivePath = tempZipPath.Combine("git-lfs"); + + var downloadGitMd5Task = new DownloadTextTask(TaskManager.Instance.Token, + environment.FileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt", + gitArchiveFilePath); + + var downloadGitTask = new DownloadTask(TaskManager.Instance.Token, environment.FileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip", + gitArchiveFilePath, retryCount: 1); + + var downloadGitLfsMd5Task = new DownloadTextTask(TaskManager.Instance.Token, environment.FileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt", + gitLfsArchivePath); + + var downloadGitLfsTask = new DownloadTask(TaskManager.Instance.Token, environment.FileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip", + gitLfsArchivePath, retryCount: 1); + + return downloadGitMd5Task + .Then((b, s) => { + downloadGitTask.ValidationHash = s; + }) + .Then(downloadGitTask) + .Then(downloadGitLfsMd5Task) + .Then((b, s) => { + downloadGitLfsTask.ValidationHash = s; + }) + .Then(downloadGitLfsTask); } private bool IsGitExtracted() diff --git a/src/GitHub.Api/Primitives/UriString.cs b/src/GitHub.Api/Primitives/UriString.cs index 509076aaa..7e9b58cce 100644 --- a/src/GitHub.Api/Primitives/UriString.cs +++ b/src/GitHub.Api/Primitives/UriString.cs @@ -71,7 +71,8 @@ void SetUri(Uri uri) Host = uri.Host; if (uri.Segments.Any()) { - RepositoryName = GetRepositoryName(uri.Segments.Last()); + Filename = uri.Segments.Last(); + RepositoryName = GetRepositoryName(Filename); } if (uri.Segments.Length > 2) @@ -86,7 +87,8 @@ void SetFilePath(Uri uri) { Host = ""; Owner = ""; - RepositoryName = GetRepositoryName(uri.Segments.Last()); + Filename = uri.Segments.Last(); + RepositoryName = GetRepositoryName(Filename); IsFileUri = true; } @@ -94,7 +96,8 @@ void SetFilePath(string path) { Host = ""; Owner = ""; - RepositoryName = GetRepositoryName(path.Replace("/", @"\").RightAfterLast(@"\")); + Filename = path.Replace("/", @"\").RightAfterLast(@"\"); + RepositoryName = GetRepositoryName(Filename); IsFileUri = true; } @@ -131,6 +134,7 @@ bool ParseScpSyntax(string scpString) public bool IsValidUri => url != null; public string Protocol => url?.Scheme; + public string Filename { get; private set; } /// /// Attempts a best-effort to convert the remote origin to a GitHub Repository URL. diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index b31ce5f09..6d5297243 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -7,7 +7,7 @@ namespace GitHub.Unity { - public class Utils + public static class Utils { public static bool Copy(Stream source, Stream destination, int chunkSize) { @@ -61,7 +61,9 @@ public static bool Copy(Stream source, Stream destination, int chunkSize, long t timeToFinish = Math.Max(1L, (long)((totalSize - totalRead) / (averageSpeed / progressUpdateRate))); - if (!progress(totalRead, timeToFinish)) + Logging.Debug($"totalRead: {totalRead} of {totalSize}"); + success = progress(totalRead, timeToFinish); + if (!success) break; } } @@ -73,6 +75,64 @@ public static bool Copy(Stream source, Stream destination, int chunkSize, long t return success; } + + public static bool Download(ILogging logger, UriString url, + Stream destinationStream, + Func onProgress) + { + long bytes = destinationStream.Length; + + var expectingResume = bytes >= 0; + + var webRequest = (HttpWebRequest)WebRequest.Create(url); + + if (expectingResume) + { + // classlib for 3.5 doesn't take long overloads... + webRequest.AddRange((int)bytes); + } + + webRequest.Method = "GET"; + webRequest.Timeout = 3000; + + if (expectingResume) + logger.Trace($"Resuming download of {url}"); + else + logger.Trace($"Downloading {url}"); + + using (var webResponse = (HttpWebResponse) webRequest.GetResponseWithoutException()) + { + var httpStatusCode = webResponse.StatusCode; + logger.Trace($"Downloading {url} StatusCode:{(int)webResponse.StatusCode}"); + + if (expectingResume && httpStatusCode == HttpStatusCode.RequestedRangeNotSatisfiable) + { + onProgress(bytes, bytes); + return true; + } + + if (!(httpStatusCode == HttpStatusCode.OK || httpStatusCode == HttpStatusCode.PartialContent)) + { + return false; + } + + var responseLength = webResponse.ContentLength; + if (expectingResume) + { + if (!onProgress(bytes, bytes + responseLength)) + return false; + } + + using (var responseStream = webResponse.GetResponseStream()) + { + return Copy(responseStream, destinationStream, 8192, responseLength, + (totalRead, timeToFinish) => { + return onProgress(totalRead, responseLength); + } + , 100); + } + } + } } public static class WebRequestExtensions @@ -95,152 +155,127 @@ public static WebResponse GetResponseWithoutException(this WebRequest request) } } - class DownloadTask : TaskBase + class DownloadTask : TaskBase { - private readonly IFileSystem fileSystem; + protected readonly IFileSystem fileSystem; private long bytes; private bool restarted; - public float Progress { get; set; } - - public DownloadTask(CancellationToken token, IFileSystem fileSystem, string url, string destination, string validationHash = null, int retryCount = 0) + public DownloadTask(CancellationToken token, + IFileSystem fileSystem, UriString url, + NPath targetDirectory = null, + string filename = null, + string validationHash = null, int retryCount = 0) : base(token) { this.fileSystem = fileSystem; ValidationHash = validationHash; RetryCount = retryCount; Url = url; - Destination = destination; - Name = "DownloadTask"; + Filename = filename ?? url.Filename; + TargetDirectory = targetDirectory ?? NPath.CreateTempDirectory("ghu"); + Name = nameof(DownloadTask); } - protected override void Run(bool success) + protected override string RunWithReturn(bool success) { - base.Run(success); + var result = base.RunWithReturn(success); RaiseOnStart(); - var attempts = 0; try { - bool result; - do - { - Logger.Trace($"Download of {Url} Attempt {attempts + 1} of {RetryCount + 1}"); - result = Download(); - if (result && ValidationHash != null) - { - var md5 = fileSystem.CalculateFileMD5(Destination); - result = md5.Equals(ValidationHash, StringComparison.CurrentCultureIgnoreCase); - - if (!result) - { - Logger.Warning($"Downloaded MD5 {md5} does not match {ValidationHash}. Deleting {Destination}."); - fileSystem.FileDelete(Destination); - } - else - { - Logger.Trace($"Download confirmed {md5}"); - break; - } - } - } while (attempts++ < RetryCount); - - if (!result) - { - throw new DownloadException("Error downloading file"); - } + result = RunDownload(success); } catch (Exception ex) { Errors = ex.Message; - if (!RaiseFaultHandlers(new DownloadException("Error downloading file", ex))) + if (!RaiseFaultHandlers(ex)) throw; } finally { - RaiseOnEnd(); + RaiseOnEnd(result); } - } - protected virtual void UpdateProgress(float progress) - { - Progress = progress; + return result; } - public bool Download() + /// + /// The actual functionality to download with optional hash verification + /// subclasses that wish to return the contents of the downloaded file + /// or do something else with it can override this instead of RunWithReturn. + /// If you do, you must call RaiseOnStart()/RaiseOnEnd() + /// + /// + /// + protected virtual string RunDownload(bool success) { - var fileInfo = new FileInfo(Destination); - if (fileSystem.FileExists(Destination)) - { - var fileLength = fileSystem.FileLength(Destination); - if (fileLength > 0) - { - bytes = fileInfo.Length; - restarted = true; - } - else if (fileLength == 0) - { - fileSystem.FileDelete(Destination); - } - } - - var expectingResume = restarted && bytes > 0; - - var webRequest = (HttpWebRequest)WebRequest.Create(Url); - - if (expectingResume) - { - // TODO: fix classlibs to take long overloads - webRequest.AddRange((int)bytes); - } - - webRequest.Method = "GET"; - webRequest.Timeout = 3000; - - if (expectingResume) - Logger.Trace($"Resuming download of {Url} to {Destination}"); - else - Logger.Trace($"Downloading {Url} to {Destination}"); - - using (var webResponse = (HttpWebResponse) webRequest.GetResponseWithoutException()) + Exception exception = null; + var attempts = 0; + bool result = false; + do { - var httpStatusCode = webResponse.StatusCode; - Logger.Trace($"Downloading {Url} StatusCode:{(int)webResponse.StatusCode}"); + if (Token.IsCancellationRequested) + break; - if (expectingResume && httpStatusCode == HttpStatusCode.RequestedRangeNotSatisfiable) - { - UpdateProgress(1); - return true; - } + exception = null; - if (!(httpStatusCode == HttpStatusCode.OK || httpStatusCode == HttpStatusCode.PartialContent)) + try { - return false; - } + Logger.Trace($"Download of {Url} to {Destination} Attempt {attempts + 1} of {RetryCount + 1}"); - var responseLength = webResponse.ContentLength; - if (expectingResume) - { - UpdateProgress(bytes / (float)responseLength); - } - - using (var responseStream = webResponse.GetResponseStream()) - { using (var destinationStream = fileSystem.OpenWrite(Destination, FileMode.Append)) { - if (Token.IsCancellationRequested) - return false; + result = Utils.Download(Logger, Url, destinationStream, + (value, total) => + { + UpdateProgress(value, total); + return !Token.IsCancellationRequested; + }); + } + + if (result && ValidationHash != null) + { + var md5 = fileSystem.CalculateFileMD5(TargetDirectory); + result = md5.Equals(ValidationHash, StringComparison.CurrentCultureIgnoreCase); - return Utils.Copy(responseStream, destinationStream, 8192, responseLength, null, 100); + if (!result) + { + Logger.Warning($"Downloaded MD5 {md5} does not match {ValidationHash}. Deleting {TargetDirectory}."); + fileSystem.FileDelete(TargetDirectory); + } + else + { + Logger.Trace($"Download confirmed {md5}"); + break; + } } } + catch (Exception ex) + { + exception = new DownloadException("Error downloading file", ex); + } + } while (attempts++ < RetryCount); + + if (!result) + { + if (exception == null) + exception = new DownloadException("Error downloading file"); + throw exception; } + + return Destination; } - protected string Url { get; } - protected string Destination { get; } + public UriString Url { get; } + + public NPath TargetDirectory { get; } + + public string Filename { get; } + + public NPath Destination { get { return TargetDirectory?.Combine(Filename); } } public string ValidationHash { get; set; } @@ -256,46 +291,33 @@ public DownloadException(string message, Exception innerException) : base(messag { } } - class DownloadTextTask : TaskBase + class DownloadTextTask : DownloadTask { - public float Progress { get; set; } - - public DownloadTextTask(CancellationToken token, string url) - : base(token) + public DownloadTextTask(CancellationToken token, + IFileSystem fileSystem, UriString url, + NPath targetDirectory = null, + string filename = null, + int retryCount = 0) + : base(token, fileSystem, url, targetDirectory, filename, retryCount: retryCount) { - Url = url; - Name = "DownloadTask"; + Name = nameof(DownloadTextTask); } - protected override string RunWithReturn(bool success) + protected override string RunDownload(bool success) { - var result = base.RunWithReturn(success); + string result = null; RaiseOnStart(); try { - Logger.Trace($"Downloading {Url}"); - var webRequest = WebRequest.Create(Url); - webRequest.Method = "GET"; - webRequest.Timeout = 3000; - - using (var webResponse = (HttpWebResponse)webRequest.GetResponseWithoutException()) - { - var webResponseCharacterSet = webResponse.CharacterSet ?? Encoding.UTF8.BodyName; - var encoding = Encoding.GetEncoding(webResponseCharacterSet); - - using (var responseStream = webResponse.GetResponseStream()) - using (var reader = new StreamReader(responseStream, encoding)) - { - result = reader.ReadToEnd(); - } - } + result = base.RunDownload(success); + result = fileSystem.ReadAllText(result, Encoding.UTF8); } catch (Exception ex) { Errors = ex.Message; - if (!RaiseFaultHandlers(new DownloadException("Error downloading text", ex))) + if (!RaiseFaultHandlers(ex)) throw; } finally @@ -305,12 +327,5 @@ protected override string RunWithReturn(bool success) return result; } - - protected virtual void UpdateProgress(float progress) - { - Progress = progress; - } - - protected string Url { get; } } } diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index d54f24d76..901d8d3a0 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -14,6 +14,7 @@ public interface ITask : IAsyncResult ITask Defer(Func continueWith, TaskAffinity affinity = TaskAffinity.Concurrent, bool always = false); ITask Start(); ITask Start(TaskScheduler scheduler); + ITask Progress(Action progressHandler); void Wait(); bool Wait(int milliseconds); @@ -37,6 +38,7 @@ public interface ITask : ITask ITask Finally(Action continuation, TaskAffinity affinity = TaskAffinity.Concurrent); new ITask Start(); new ITask Start(TaskScheduler scheduler); + new ITask Progress(Action progressHandler); TResult Result { get; } new Task Task { get; } new event Action> OnStart; @@ -69,8 +71,12 @@ public abstract class TaskBase : ITask protected event Func faultHandler; private event Action finallyHandler; + protected event Action progressHandler; + + private Progress progress; public TaskBase(CancellationToken token) + : this() { Guard.ArgumentNotNull(token, "token"); @@ -79,6 +85,7 @@ public TaskBase(CancellationToken token) } public TaskBase(Task task) + : this() { Task = new Task(t => { @@ -106,7 +113,10 @@ public TaskBase(Task task) }, task, Token, TaskCreationOptions.None); } - protected TaskBase() {} + protected TaskBase() + { + this.progress = new Progress { Task = this }; + } public virtual T Then(T cont, bool always = false) where T : ITask @@ -193,6 +203,16 @@ internal void SetFaultHandler(TaskBase handler) DependsOn?.SetFaultHandler(handler); } + /// + /// Progress provides progress reporting from the task (on the same thread) + /// + public ITask Progress(Action handler) + { + Guard.ArgumentNotNull(handler, nameof(handler)); + this.progressHandler += handler; + return this; + } + public virtual ITask Start() { var depends = GetTopMostTaskInCreatedState(); @@ -301,8 +321,14 @@ protected virtual void RaiseOnStart() protected virtual void RaiseOnEnd() { + var success = Task.Status != TaskStatus.Faulted; + if (success) + { + + } OnEnd?.Invoke(this); - if (Task.Status != TaskStatus.Faulted && continuation == null) + // if it's the last task of the chain and all went well (otherwise finally has been called already) + if (success && continuation == null) finallyHandler?.Invoke(); //Logger.Trace($"Finished {ToString()}"); } @@ -336,6 +362,12 @@ protected Exception GetThrownException() return DependsOn.GetThrownException(); } + protected void UpdateProgress(long value, long total) + { + progress.UpdateProgress(value, total); + progressHandler?.Invoke(progress); + } + protected class DeferredContinuation { public bool Always; @@ -491,7 +523,7 @@ public override T Then(T continuation, bool always = false) } /// - /// Catch runs right when the exception happens (on the same threaD) + /// Catch runs right when the exception happens (on the same thread) /// Return false if you want other Catch statements on the chain to also /// get called for this exception /// @@ -561,11 +593,22 @@ public ITask Finally(Action continuation, TaskAffinity return this; } + /// + /// Progress provides progress reporting from the task (on the same thread) + /// + public new ITask Progress(Action handler) + { + Guard.ArgumentNotNull(handler, nameof(handler)); + this.progressHandler += handler; + return this; + } + protected virtual TResult RunWithReturn(bool success) { base.Run(success); return default(TResult); } + protected override void RaiseOnStart() { //Logger.Trace($"Executing {ToString()}"); diff --git a/src/tests/IntegrationTests/BaseIntegrationTest.cs b/src/tests/IntegrationTests/BaseIntegrationTest.cs index fce868c0b..2e490cff2 100644 --- a/src/tests/IntegrationTests/BaseIntegrationTest.cs +++ b/src/tests/IntegrationTests/BaseIntegrationTest.cs @@ -4,6 +4,7 @@ using GitHub.Unity; using NCrunch.Framework; using System.Threading; +using NSubstitute; namespace IntegrationTests { @@ -14,10 +15,26 @@ class BaseIntegrationTest protected ILogging Logger { get; private set; } public IEnvironment Environment { get; set; } public IRepository Repository => Environment.Repository; + public ICacheContainer CacheContainer { get; set; } protected TestUtils.SubstituteFactory Factory { get; set; } protected static NPath SolutionDirectory => TestContext.CurrentContext.TestDirectory.ToNPath(); + protected void InitializeEnvironment(NPath repoPath, + NPath environmentPath = null, + bool enableEnvironmentTrace = false, + bool initializeRepository = true + ) + { + CacheContainer = Substitute.For(); + Environment = new IntegrationTestEnvironment(CacheContainer, + repoPath, + SolutionDirectory, + environmentPath, + enableEnvironmentTrace, + initializeRepository); + } + [TestFixtureSetUp] public void TestFixtureSetUp() { diff --git a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs index 17df8feac..37261448a 100644 --- a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs +++ b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs @@ -14,15 +14,11 @@ class BasePlatformIntegrationTest : BaseTaskManagerTest protected IProcessManager ProcessManager { get; private set; } protected IProcessEnvironment GitEnvironment => Platform.GitEnvironment; protected IGitClient GitClient { get; set; } - public ICacheContainer CacheContainer { get; set; } protected void InitializePlatform(NPath repoPath, NPath environmentPath, bool enableEnvironmentTrace, bool setupGit = true) { InitializeTaskManager(); - - CacheContainer = Substitute.For(); - Environment = new IntegrationTestEnvironment(CacheContainer, repoPath, SolutionDirectory, environmentPath, - enableEnvironmentTrace); + InitializeEnvironment(repoPath, environmentPath, enableEnvironmentTrace); Platform = new Platform(Environment); ProcessManager = new ProcessManager(Environment, GitEnvironment, TaskManager.Token); diff --git a/src/tests/IntegrationTests/BaseTaskManagerTest.cs b/src/tests/IntegrationTests/BaseTaskManagerTest.cs index 7b209f0f8..a7c646ce1 100644 --- a/src/tests/IntegrationTests/BaseTaskManagerTest.cs +++ b/src/tests/IntegrationTests/BaseTaskManagerTest.cs @@ -8,6 +8,12 @@ class BaseTaskManagerTest : BaseIntegrationTest protected ITaskManager TaskManager { get; private set; } protected SynchronizationContext SyncContext { get; set; } + public override void OnSetup() + { + base.OnSetup(); + InitializeTaskManager(); + } + protected void InitializeTaskManager() { TaskManager = new TaskManager(); diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 2d400aef1..d53f05890 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -1,31 +1,35 @@ using System; using System.Linq; -using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using FluentAssertions; using GitHub.Unity; using NUnit.Framework; +using System.Diagnostics; namespace IntegrationTests.Download { [TestFixture] - class DownloadTaskTests: BaseTaskManagerTest + class DownloadTaskTests : BaseTaskManagerTest { private const string TestDownload = "http://ipv4.download.thinkbroadband.com/5MB.zip"; private const string TestDownloadMD5 = "b3215c06647bc550406a9c8ccc378756"; + public override void OnSetup() + { + base.OnSetup(); + InitializeEnvironment(TestBasePath, initializeRepository: false); + } + [Test] public async Task TestDownloadTask() { - InitializeTaskManager(); - - var fileSystem = new FileSystem(); + var fileSystem = Environment.FileSystem; var downloadPath = TestBasePath.Combine("5MB.zip"); var downloadHalfPath = TestBasePath.Combine("5MB-split.zip"); - var downloadTask = new DownloadTask(CancellationToken.None, fileSystem, TestDownload, downloadPath); + var downloadTask = new DownloadTask(TaskManager.Token, fileSystem, TestDownload, TestBasePath); await downloadTask.StartAwait(); var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); @@ -42,7 +46,8 @@ public async Task TestDownloadTask() var cutDownloadPathBytes = downloadPathBytes.Take(takeCount).ToArray(); fileSystem.WriteAllBytes(downloadHalfPath, cutDownloadPathBytes); - downloadTask = new DownloadTask(CancellationToken.None, fileSystem, TestDownload, downloadHalfPath, TestDownloadMD5, 1); + downloadTask = new DownloadTask(TaskManager.Token, fileSystem, TestDownload, + TestBasePath, validationHash: TestDownloadMD5); await downloadTask.StartAwait(); var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadHalfPath); @@ -55,9 +60,7 @@ public async Task TestDownloadTask() [Test] public void TestDownloadFailure() { - InitializeTaskManager(); - - var fileSystem = new FileSystem(); + var fileSystem = Environment.FileSystem; var downloadPath = TestBasePath.Combine("5MB.zip"); @@ -66,7 +69,8 @@ public void TestDownloadFailure() var autoResetEvent = new AutoResetEvent(false); - var downloadTask = new DownloadTask(CancellationToken.None, fileSystem, "http://www.unknown.com/5MB.gz", downloadPath, null, 1) + var downloadTask = new DownloadTask(TaskManager.Token, fileSystem, + "http://www.unknown.com/5MB.gz", TestBasePath) .Finally((b, exception) => { taskFailed = !b; exceptionThrown = exception; @@ -84,9 +88,11 @@ public void TestDownloadFailure() [Test] public void TestDownloadTextTask() { - InitializeTaskManager(); + var fileSystem = Environment.FileSystem; - var downloadTask = new DownloadTextTask(CancellationToken.None, "https://github.com/robots.txt"); + var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, + "https://github.com/robots.txt", + TestBasePath); var result = downloadTask.Start().Result; var resultLines = result.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); resultLines[0].Should().Be("# If you would like to crawl GitHub contact us at support@github.com."); @@ -95,9 +101,10 @@ public void TestDownloadTextTask() [Test] public void TestDownloadTextFailure() { - InitializeTaskManager(); + var fileSystem = Environment.FileSystem; - var downloadTask = new DownloadTextTask(CancellationToken.None, "https://ggggithub.com/robots.txt"); + var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, + "https://ggggithub.com/robots.txt"); var exceptionThrown = false; try @@ -115,24 +122,27 @@ public void TestDownloadTextFailure() [Test] public void TestDownloadFileAndHash() { - InitializeTaskManager(); + var fileSystem = Environment.FileSystem; var gitArchivePath = TestBasePath.Combine("git.zip"); var gitLfsArchivePath = TestBasePath.Combine("git-lfs.zip"); - var fileSystem = new FileSystem(); + var downloadGitMd5Task = new DownloadTextTask(TaskManager.Token, fileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt?cb=1", + TestBasePath); - var downloadGitMd5Task = new DownloadTextTask(CancellationToken.None, - "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt?cb=1"); + var downloadGitTask = new DownloadTask(TaskManager.Token, fileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip", + TestBasePath); - var downloadGitTask = new DownloadTask(CancellationToken.None, fileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git.zip", gitArchivePath, retryCount: 1); + var downloadGitLfsMd5Task = new DownloadTextTask(TaskManager.Token, fileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt?cb=1", + TestBasePath); - var downloadGitLfsMd5Task = new DownloadTextTask(CancellationToken.None, - "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt?cb=1"); - var downloadGitLfsTask = new DownloadTask(CancellationToken.None, fileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip", gitLfsArchivePath, retryCount: 1); + var downloadGitLfsTask = new DownloadTask(TaskManager.Token, fileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip", + TestBasePath); var result = true; Exception exception = null; @@ -163,5 +173,50 @@ public void TestDownloadFileAndHash() result.Should().BeTrue(); exception.Should().BeNull(); } + + [Test] + public void TestDownloadShutdownTimeWhenInterrupted() + { + var fileSystem = Environment.FileSystem; + + var gitArchivePath = TestBasePath.Combine("git.zip"); + + var evtStop = new AutoResetEvent(false); + var evtFinally = new AutoResetEvent(false); + Exception exception = null; + + var watch = new Stopwatch(); + + var downloadGitTask = new DownloadTask(TaskManager.Token, fileSystem, + "https://ghfvs-installer.github.com/unity/portable_git/git.zip", + TestBasePath) + + // An exception is thrown when we stop the task manager + // since we're stopping the task manager, no other tasks + // will run, which means we can only hook with Catch + // or with the Finally overload that runs on the same thread (not as a task) + .Catch(e => + { + exception = e; + evtFinally.Set(); + }) + .Progress(p => + { + if (p.Percentage > 0.2) + evtStop.Set(); + }); + + downloadGitTask.Start(); + + evtStop.WaitOne(); + + watch.Start(); + TaskManager.Dispose(); + evtFinally.WaitOne(); + watch.Stop(); + + exception.Should().NotBeNull(); + watch.ElapsedMilliseconds.Should().BeLessThan(250); + } } } diff --git a/src/tests/IntegrationTests/IntegrationTestEnvironment.cs b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs index 3951f9537..c1d5d3b9e 100644 --- a/src/tests/IntegrationTests/IntegrationTestEnvironment.cs +++ b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs @@ -12,8 +12,12 @@ class IntegrationTestEnvironment : IEnvironment private DefaultEnvironment defaultEnvironment; - public IntegrationTestEnvironment(ICacheContainer cacheContainer, NPath repoPath, NPath solutionDirectory, NPath environmentPath = null, - bool enableTrace = false) + public IntegrationTestEnvironment(ICacheContainer cacheContainer, + NPath repoPath, + NPath solutionDirectory, + NPath environmentPath = null, + bool enableTrace = false, + bool initializeRepository = true) { defaultEnvironment = new DefaultEnvironment(cacheContainer); defaultEnvironment.FileSystem.SetCurrentDirectory(repoPath); @@ -29,7 +33,9 @@ public IntegrationTestEnvironment(ICacheContainer cacheContainer, NPath repoPath var installPath = solutionDirectory.Parent.Parent.Combine("src", "GitHub.Api"); Initialize(UnityVersion, installPath, solutionDirectory, repoPath.Combine("Assets")); - InitializeRepository(); + + if (initializeRepository) + InitializeRepository(); this.enableTrace = enableTrace; From 2693fb8c86e086c0f7cae537bde53d5c2618db7f Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 29 Jan 2018 20:27:53 +0100 Subject: [PATCH 0115/1008] Kinda need to know which tests are running at what time in the log --- .../IntegrationTests/Download/DownloadTaskTests.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index d53f05890..bf5245b25 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -24,6 +24,8 @@ public override void OnSetup() [Test] public async Task TestDownloadTask() { + Logger.Info("Starting Test: TestDownloadTask"); + var fileSystem = Environment.FileSystem; var downloadPath = TestBasePath.Combine("5MB.zip"); @@ -60,6 +62,8 @@ public async Task TestDownloadTask() [Test] public void TestDownloadFailure() { + Logger.Info("Starting Test: TestDownloadFailure"); + var fileSystem = Environment.FileSystem; var downloadPath = TestBasePath.Combine("5MB.zip"); @@ -88,6 +92,8 @@ public void TestDownloadFailure() [Test] public void TestDownloadTextTask() { + Logger.Info("Starting Test: TestDownloadTextTask"); + var fileSystem = Environment.FileSystem; var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, @@ -101,6 +107,8 @@ public void TestDownloadTextTask() [Test] public void TestDownloadTextFailure() { + Logger.Info("Starting Test: TestDownloadTextFailure"); + var fileSystem = Environment.FileSystem; var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, @@ -122,6 +130,8 @@ public void TestDownloadTextFailure() [Test] public void TestDownloadFileAndHash() { + Logger.Info("Starting Test: TestDownloadFileAndHash"); + var fileSystem = Environment.FileSystem; var gitArchivePath = TestBasePath.Combine("git.zip"); @@ -177,6 +187,8 @@ public void TestDownloadFileAndHash() [Test] public void TestDownloadShutdownTimeWhenInterrupted() { + Logger.Info("Starting Test: TestDownloadShutdownTimeWhenInterrupted"); + var fileSystem = Environment.FileSystem; var gitArchivePath = TestBasePath.Combine("git.zip"); From f3bb2f86ff5003a89f044be1e36d0f9e5215c638 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 29 Jan 2018 20:49:19 +0100 Subject: [PATCH 0116/1008] Resume is only if we actually had some existing data :P --- src/GitHub.Api/Tasks/DownloadTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 6d5297243..c7e4ca111 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -82,7 +82,7 @@ public static bool Download(ILogging logger, UriString url, { long bytes = destinationStream.Length; - var expectingResume = bytes >= 0; + var expectingResume = bytes > 0; var webRequest = (HttpWebRequest)WebRequest.Create(url); From f6826b5f2e37f1fa0e6da021c6a6a85200aeebae Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 29 Jan 2018 21:32:35 +0100 Subject: [PATCH 0117/1008] Add test for new UriString.Filename property --- .../UnitTests/Primitives/UriStringTests.cs | 21 +++++++++++++++++++ src/tests/UnitTests/UnitTests.csproj | 1 + 2 files changed, 22 insertions(+) create mode 100644 src/tests/UnitTests/Primitives/UriStringTests.cs diff --git a/src/tests/UnitTests/Primitives/UriStringTests.cs b/src/tests/UnitTests/Primitives/UriStringTests.cs new file mode 100644 index 000000000..14cce01d1 --- /dev/null +++ b/src/tests/UnitTests/Primitives/UriStringTests.cs @@ -0,0 +1,21 @@ +using GitHub.Unity; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UnitTests.Primitives +{ + [TestFixture] + class UriStringTests + { + [TestCase("http://url.com/path/file.zip?cb=1", "file.zip")] + [TestCase("http://url.com/path/file?cb=1", "file")] + public void FilenameParsing(string url, string expectedFilename) + { + var uriString = new UriString(url); + Assert.AreEqual(expectedFilename, uriString.Filename); + } + } +} diff --git a/src/tests/UnitTests/UnitTests.csproj b/src/tests/UnitTests/UnitTests.csproj index 76b20c6e9..763adcc59 100644 --- a/src/tests/UnitTests/UnitTests.csproj +++ b/src/tests/UnitTests/UnitTests.csproj @@ -93,6 +93,7 @@ + From e61d48cd1be6d669020d926ced06d6be09501e69 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 29 Jan 2018 21:33:12 +0100 Subject: [PATCH 0118/1008] Speed up tests a bit --- .../Download/DownloadTaskTests.cs | 61 +++++++------------ 1 file changed, 21 insertions(+), 40 deletions(-) diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index bf5245b25..15549648b 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -12,9 +12,6 @@ namespace IntegrationTests.Download [TestFixture] class DownloadTaskTests : BaseTaskManagerTest { - private const string TestDownload = "http://ipv4.download.thinkbroadband.com/5MB.zip"; - private const string TestDownloadMD5 = "b3215c06647bc550406a9c8ccc378756"; - public override void OnSetup() { base.OnSetup(); @@ -28,17 +25,20 @@ public async Task TestDownloadTask() var fileSystem = Environment.FileSystem; - var downloadPath = TestBasePath.Combine("5MB.zip"); - var downloadHalfPath = TestBasePath.Combine("5MB-split.zip"); + var gitLfs = new UriString("https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip"); + var gitLfsMd5 = new UriString("https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt?cb=1"); - var downloadTask = new DownloadTask(TaskManager.Token, fileSystem, TestDownload, TestBasePath); - await downloadTask.StartAwait(); + var md5 = await new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath) + .StartAwait(); - var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); - Logger.Trace("File size {0} bytes", downloadPathBytes.Length); + var downloadPath = await new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath) + .StartAwait(); var md5Sum = fileSystem.CalculateFileMD5(downloadPath); - md5Sum.Should().Be(TestDownloadMD5); + md5Sum.Should().BeEquivalentTo(md5); + + var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); + Logger.Trace("File size {0} bytes", downloadPathBytes.Length); var random = new Random(); var takeCount = random.Next(downloadPathBytes.Length); @@ -46,17 +46,16 @@ public async Task TestDownloadTask() Logger.Trace("Cutting the first {0} Bytes", downloadPathBytes.Length - takeCount); var cutDownloadPathBytes = downloadPathBytes.Take(takeCount).ToArray(); - fileSystem.WriteAllBytes(downloadHalfPath, cutDownloadPathBytes); + fileSystem.WriteAllBytes(downloadPath, cutDownloadPathBytes); - downloadTask = new DownloadTask(TaskManager.Token, fileSystem, TestDownload, - TestBasePath, validationHash: TestDownloadMD5); - await downloadTask.StartAwait(); + downloadPath = await new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath) + .StartAwait(); - var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadHalfPath); + var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadPath); Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); md5Sum = fileSystem.CalculateFileMD5(downloadPath); - md5Sum.Should().Be(TestDownloadMD5); + md5Sum.Should().BeEquivalentTo(md5); } [Test] @@ -134,38 +133,21 @@ public void TestDownloadFileAndHash() var fileSystem = Environment.FileSystem; - var gitArchivePath = TestBasePath.Combine("git.zip"); - var gitLfsArchivePath = TestBasePath.Combine("git-lfs.zip"); - - var downloadGitMd5Task = new DownloadTextTask(TaskManager.Token, fileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt?cb=1", - TestBasePath); - - var downloadGitTask = new DownloadTask(TaskManager.Token, fileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git.zip", - TestBasePath); + var gitLfs = new UriString("https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip"); + var gitLfsMd5 = new UriString("https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt?cb=1"); var downloadGitLfsMd5Task = new DownloadTextTask(TaskManager.Token, fileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt?cb=1", - TestBasePath); - + gitLfsMd5, TestBasePath); var downloadGitLfsTask = new DownloadTask(TaskManager.Token, fileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip", - TestBasePath); + gitLfs, TestBasePath); var result = true; Exception exception = null; var autoResetEvent = new AutoResetEvent(false); - downloadGitMd5Task - .Then((b, s) => - { - downloadGitTask.ValidationHash = s; - }) - .Then(downloadGitTask) - .Then(downloadGitLfsMd5Task) + downloadGitLfsMd5Task .Then((b, s) => { downloadGitLfsTask.ValidationHash = s; @@ -214,8 +196,7 @@ public void TestDownloadShutdownTimeWhenInterrupted() }) .Progress(p => { - if (p.Percentage > 0.2) - evtStop.Set(); + evtStop.Set(); }); downloadGitTask.Start(); From f71de4ef061d31c92e38983b851062bcbe7bf6bd Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Tue, 30 Jan 2018 13:32:11 +0100 Subject: [PATCH 0119/1008] Use a local webserver to serve files for testing. Fix partial downloads. --- GitHub.Unity.sln | 9 + src/GitHub.Api/GitHub.Api.csproj | 1 + src/GitHub.Api/IO/Utils.cs | 147 ++++++++++ src/GitHub.Api/Tasks/DownloadTask.cs | 154 +---------- .../IntegrationTests/BaseIntegrationTest.cs | 4 +- .../Download/DownloadTaskTests.cs | 65 +++-- .../IntegrationTests/IntegrationTests.csproj | 4 + src/tests/TestWebServer/HttpServer.cs | 261 ++++++++++++++++++ .../TestWebServer/Properties/AssemblyInfo.cs | 36 +++ src/tests/TestWebServer/TestWebServer.csproj | 63 +++++ src/tests/TestWebServer/files/git-lfs.zip | 3 + .../TestWebServer/files/git-lfs.zip.MD5.txt | 1 + 12 files changed, 564 insertions(+), 184 deletions(-) create mode 100644 src/GitHub.Api/IO/Utils.cs create mode 100644 src/tests/TestWebServer/HttpServer.cs create mode 100644 src/tests/TestWebServer/Properties/AssemblyInfo.cs create mode 100644 src/tests/TestWebServer/TestWebServer.csproj create mode 100644 src/tests/TestWebServer/files/git-lfs.zip create mode 100644 src/tests/TestWebServer/files/git-lfs.zip.MD5.txt diff --git a/GitHub.Unity.sln b/GitHub.Unity.sln index e5ce29f0a..db12af918 100644 --- a/GitHub.Unity.sln +++ b/GitHub.Unity.sln @@ -27,6 +27,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TaskSystem", "src\tests\Tas EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApp", "src\tests\TestApp\TestApp.csproj", "{08B87D2A-8CF1-4211-B7AA-5209F00F72F8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestWebServer", "src\tests\TestWebServer\TestWebServer.csproj", "{3DD3451C-30FA-4294-A3A9-1E080342F867}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -94,6 +96,12 @@ Global {08B87D2A-8CF1-4211-B7AA-5209F00F72F8}.dev|Any CPU.Build.0 = Debug|Any CPU {08B87D2A-8CF1-4211-B7AA-5209F00F72F8}.Release|Any CPU.ActiveCfg = Release|Any CPU {08B87D2A-8CF1-4211-B7AA-5209F00F72F8}.Release|Any CPU.Build.0 = Release|Any CPU + {3DD3451C-30FA-4294-A3A9-1E080342F867}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3DD3451C-30FA-4294-A3A9-1E080342F867}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3DD3451C-30FA-4294-A3A9-1E080342F867}.dev|Any CPU.ActiveCfg = Debug|Any CPU + {3DD3451C-30FA-4294-A3A9-1E080342F867}.dev|Any CPU.Build.0 = Debug|Any CPU + {3DD3451C-30FA-4294-A3A9-1E080342F867}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3DD3451C-30FA-4294-A3A9-1E080342F867}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -106,5 +114,6 @@ Global {66A1D219-F61D-4AE4-9BD7-AAEB97276FFF} = {D17F1B4C-42DC-4E78-BCEF-9F239A084C4D} {1A382F40-FD9E-43E1-89C1-320073F35CE9} = {D17F1B4C-42DC-4E78-BCEF-9F239A084C4D} {08B87D2A-8CF1-4211-B7AA-5209F00F72F8} = {D17F1B4C-42DC-4E78-BCEF-9F239A084C4D} + {3DD3451C-30FA-4294-A3A9-1E080342F867} = {D17F1B4C-42DC-4E78-BCEF-9F239A084C4D} EndGlobalSection EndGlobal diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 6c6aa80ef..cf42b3574 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -157,6 +157,7 @@ + diff --git a/src/GitHub.Api/IO/Utils.cs b/src/GitHub.Api/IO/Utils.cs new file mode 100644 index 000000000..b9f62f0d0 --- /dev/null +++ b/src/GitHub.Api/IO/Utils.cs @@ -0,0 +1,147 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Net; + +namespace GitHub.Unity +{ + public static class Utils + { + public static bool Copy(Stream source, Stream destination, + long totalSize = 0, + int chunkSize = 8192, + Func progress = null, + int progressUpdateRate = 100) + { + byte[] buffer = new byte[chunkSize]; + int bytesRead = 0; + long totalRead = 0; + float averageSpeed = -1f; + float lastSpeed = 0f; + float smoothing = 0.005f; + long readLastSecond = 0; + long timeToFinish = 0; + Stopwatch watch = null; + bool success = true; + + bool trackProgress = totalSize > 0 && progress != null; + if (trackProgress) + watch = new Stopwatch(); + + do + { + if (trackProgress) + watch.Start(); + + bytesRead = source.Read(buffer, 0, totalRead + chunkSize > totalSize ? (int)(totalSize - totalRead) : chunkSize); + + if (trackProgress) + watch.Stop(); + + totalRead += bytesRead; + + if (bytesRead > 0) + { + destination.Write(buffer, 0, bytesRead); + if (trackProgress) + { + readLastSecond += bytesRead; + if (watch.ElapsedMilliseconds >= progressUpdateRate || totalRead == totalSize || bytesRead == 0) + { + watch.Reset(); + if (bytesRead == 0) // we've reached the end + totalSize = totalRead; + + lastSpeed = readLastSecond; + readLastSecond = 0; + averageSpeed = averageSpeed < 0f + ? lastSpeed + : smoothing * lastSpeed + (1f - smoothing) * averageSpeed; + timeToFinish = Math.Max(1L, + (long)((totalSize - totalRead) / (averageSpeed / progressUpdateRate))); + + Logging.Debug($"totalRead: {totalRead} of {totalSize}"); + success = progress(totalRead, timeToFinish); + if (!success) + break; + } + } + else // we still need to call the callback if it's there, so we can abort if needed + { + success = progress?.Invoke(totalRead, timeToFinish) ?? true; + if (!success) + break; + } + } + } while (bytesRead > 0 && (totalSize == 0 || totalSize > totalRead)); + + if (totalRead > 0) + destination.Flush(); + + return success; + } + + public static bool Download(ILogging logger, UriString url, + Stream destinationStream, + Func onProgress) + { + long bytes = destinationStream.Length; + + var expectingResume = bytes > 0; + + var webRequest = (HttpWebRequest)WebRequest.Create(url); + + if (expectingResume) + { + // classlib for 3.5 doesn't take long overloads... + webRequest.AddRange((int)bytes); + } + + webRequest.Method = "GET"; + webRequest.Timeout = 5000; + + if (expectingResume) + logger.Trace($"Resuming download of {url}"); + else + logger.Trace($"Downloading {url}"); + + using (var webResponse = (HttpWebResponse) webRequest.GetResponseWithoutException()) + { + var httpStatusCode = webResponse.StatusCode; + logger.Trace($"Downloading {url} StatusCode:{(int)webResponse.StatusCode}"); + + if (expectingResume && httpStatusCode == HttpStatusCode.RequestedRangeNotSatisfiable) + { + onProgress(bytes, bytes); + return true; + } + + if (!(httpStatusCode == HttpStatusCode.OK || httpStatusCode == HttpStatusCode.PartialContent)) + { + return false; + } + + if (expectingResume && httpStatusCode == HttpStatusCode.OK) + { + expectingResume = false; + destinationStream.Seek(0, SeekOrigin.Begin); + } + + var responseLength = webResponse.ContentLength; + if (expectingResume) + { + if (!onProgress(bytes, bytes + responseLength)) + return false; + } + + using (var responseStream = webResponse.GetResponseStream()) + { + return Copy(responseStream, destinationStream, responseLength, + progress: (totalRead, timeToFinish) => { + return onProgress(totalRead, responseLength); + }); + } + } + } + } +} \ No newline at end of file diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index c7e4ca111..244514924 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.IO; using System.Net; using System.Text; @@ -7,134 +6,6 @@ namespace GitHub.Unity { - public static class Utils - { - public static bool Copy(Stream source, Stream destination, int chunkSize) - { - return Copy(source, destination, chunkSize, 0, null, 1000); - } - - public static bool Copy(Stream source, Stream destination, int chunkSize, long totalSize, - Func progress, int progressUpdateRate) - { - byte[] buffer = new byte[chunkSize]; - int bytesRead = 0; - long totalRead = 0; - float averageSpeed = -1f; - float lastSpeed = 0f; - float smoothing = 0.005f; - long readLastSecond = 0; - long timeToFinish = 0; - Stopwatch watch = null; - bool success = true; - - bool trackProgress = totalSize > 0 && progress != null; - if (trackProgress) - watch = new Stopwatch(); - - do - { - if (trackProgress) - watch.Start(); - - bytesRead = source.Read(buffer, 0, chunkSize); - - if (trackProgress) - watch.Stop(); - - totalRead += bytesRead; - - if (bytesRead > 0) - { - destination.Write(buffer, 0, bytesRead); - if (trackProgress) - { - readLastSecond += bytesRead; - if (watch.ElapsedMilliseconds >= progressUpdateRate || totalRead == totalSize) - { - watch.Reset(); - lastSpeed = readLastSecond; - readLastSecond = 0; - averageSpeed = averageSpeed < 0f - ? lastSpeed - : smoothing * lastSpeed + (1f - smoothing) * averageSpeed; - timeToFinish = Math.Max(1L, - (long)((totalSize - totalRead) / (averageSpeed / progressUpdateRate))); - - Logging.Debug($"totalRead: {totalRead} of {totalSize}"); - success = progress(totalRead, timeToFinish); - if (!success) - break; - } - } - } - } while (bytesRead > 0); - - if (totalRead > 0) - destination.Flush(); - - return success; - } - - public static bool Download(ILogging logger, UriString url, - Stream destinationStream, - Func onProgress) - { - long bytes = destinationStream.Length; - - var expectingResume = bytes > 0; - - var webRequest = (HttpWebRequest)WebRequest.Create(url); - - if (expectingResume) - { - // classlib for 3.5 doesn't take long overloads... - webRequest.AddRange((int)bytes); - } - - webRequest.Method = "GET"; - webRequest.Timeout = 3000; - - if (expectingResume) - logger.Trace($"Resuming download of {url}"); - else - logger.Trace($"Downloading {url}"); - - using (var webResponse = (HttpWebResponse) webRequest.GetResponseWithoutException()) - { - var httpStatusCode = webResponse.StatusCode; - logger.Trace($"Downloading {url} StatusCode:{(int)webResponse.StatusCode}"); - - if (expectingResume && httpStatusCode == HttpStatusCode.RequestedRangeNotSatisfiable) - { - onProgress(bytes, bytes); - return true; - } - - if (!(httpStatusCode == HttpStatusCode.OK || httpStatusCode == HttpStatusCode.PartialContent)) - { - return false; - } - - var responseLength = webResponse.ContentLength; - if (expectingResume) - { - if (!onProgress(bytes, bytes + responseLength)) - return false; - } - - using (var responseStream = webResponse.GetResponseStream()) - { - return Copy(responseStream, destinationStream, 8192, responseLength, - (totalRead, timeToFinish) => { - return onProgress(totalRead, responseLength); - } - , 100); - } - } - } - } - public static class WebRequestExtensions { public static WebResponse GetResponseWithoutException(this WebRequest request) @@ -158,8 +29,6 @@ public static WebResponse GetResponseWithoutException(this WebRequest request) class DownloadTask : TaskBase { protected readonly IFileSystem fileSystem; - private long bytes; - private bool restarted; public DownloadTask(CancellationToken token, IFileSystem fileSystem, UriString url, @@ -305,27 +174,8 @@ public DownloadTextTask(CancellationToken token, protected override string RunDownload(bool success) { - string result = null; - - RaiseOnStart(); - - try - { - result = base.RunDownload(success); - result = fileSystem.ReadAllText(result, Encoding.UTF8); - } - catch (Exception ex) - { - Errors = ex.Message; - if (!RaiseFaultHandlers(ex)) - throw; - } - finally - { - RaiseOnEnd(result); - } - - return result; + var result = base.RunDownload(success); + return fileSystem.ReadAllText(result, Encoding.UTF8); } } } diff --git a/src/tests/IntegrationTests/BaseIntegrationTest.cs b/src/tests/IntegrationTests/BaseIntegrationTest.cs index 2e490cff2..10772e7fa 100644 --- a/src/tests/IntegrationTests/BaseIntegrationTest.cs +++ b/src/tests/IntegrationTests/BaseIntegrationTest.cs @@ -36,7 +36,7 @@ protected void InitializeEnvironment(NPath repoPath, } [TestFixtureSetUp] - public void TestFixtureSetUp() + public virtual void TestFixtureSetUp() { Logger = Logging.GetLogger(GetType()); Factory = new TestUtils.SubstituteFactory(); @@ -44,7 +44,7 @@ public void TestFixtureSetUp() } [TestFixtureTearDown] - public void TestFixtureTearDown() + public virtual void TestFixtureTearDown() { } diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 15549648b..be2b50155 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -18,6 +18,20 @@ public override void OnSetup() InitializeEnvironment(TestBasePath, initializeRepository: false); } + private TestWebServer.HttpServer server; + public override void TestFixtureSetUp() + { + base.TestFixtureSetUp(); + server = new TestWebServer.HttpServer(); + Task.Factory.StartNew(server.Start); + } + + public override void TestFixtureTearDown() + { + base.TestFixtureTearDown(); + server.Stop(); + } + [Test] public async Task TestDownloadTask() { @@ -25,8 +39,8 @@ public async Task TestDownloadTask() var fileSystem = Environment.FileSystem; - var gitLfs = new UriString("https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip"); - var gitLfsMd5 = new UriString("https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt?cb=1"); + var gitLfs = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); + var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); var md5 = await new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath) .StartAwait(); @@ -40,12 +54,8 @@ public async Task TestDownloadTask() var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); Logger.Trace("File size {0} bytes", downloadPathBytes.Length); - var random = new Random(); - var takeCount = random.Next(downloadPathBytes.Length); - - Logger.Trace("Cutting the first {0} Bytes", downloadPathBytes.Length - takeCount); - - var cutDownloadPathBytes = downloadPathBytes.Take(takeCount).ToArray(); + var cutDownloadPathBytes = downloadPathBytes.Take(downloadPathBytes.Length - 1000).ToArray(); + fileSystem.FileDelete(downloadPath); fileSystem.WriteAllBytes(downloadPath, cutDownloadPathBytes); downloadPath = await new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath) @@ -65,15 +75,13 @@ public void TestDownloadFailure() var fileSystem = Environment.FileSystem; - var downloadPath = TestBasePath.Combine("5MB.zip"); - var taskFailed = false; Exception exceptionThrown = null; var autoResetEvent = new AutoResetEvent(false); var downloadTask = new DownloadTask(TaskManager.Token, fileSystem, - "http://www.unknown.com/5MB.gz", TestBasePath) + $"http://localhost:{server.Port}/nope", TestBasePath) .Finally((b, exception) => { taskFailed = !b; exceptionThrown = exception; @@ -95,12 +103,11 @@ public void TestDownloadTextTask() var fileSystem = Environment.FileSystem; - var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, - "https://github.com/robots.txt", - TestBasePath); + var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); + + var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath); var result = downloadTask.Start().Result; - var resultLines = result.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); - resultLines[0].Should().Be("# If you would like to crawl GitHub contact us at support@github.com."); + result.Should().Be("105DF1302560C5F6AA64D1930284C126"); } [Test] @@ -110,8 +117,7 @@ public void TestDownloadTextFailure() var fileSystem = Environment.FileSystem; - var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, - "https://ggggithub.com/robots.txt"); + var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, "https://ggggithub.com/robots.txt"); var exceptionThrown = false; try @@ -133,14 +139,11 @@ public void TestDownloadFileAndHash() var fileSystem = Environment.FileSystem; - var gitLfs = new UriString("https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip"); - var gitLfsMd5 = new UriString("https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt?cb=1"); - - var downloadGitLfsMd5Task = new DownloadTextTask(TaskManager.Token, fileSystem, - gitLfsMd5, TestBasePath); + var gitLfs = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); + var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); - var downloadGitLfsTask = new DownloadTask(TaskManager.Token, fileSystem, - gitLfs, TestBasePath); + var downloadGitLfsMd5Task = new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath); + var downloadGitLfsTask = new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath); var result = true; Exception exception = null; @@ -171,9 +174,9 @@ public void TestDownloadShutdownTimeWhenInterrupted() { Logger.Info("Starting Test: TestDownloadShutdownTimeWhenInterrupted"); - var fileSystem = Environment.FileSystem; + server.Delay = 100; - var gitArchivePath = TestBasePath.Combine("git.zip"); + var fileSystem = Environment.FileSystem; var evtStop = new AutoResetEvent(false); var evtFinally = new AutoResetEvent(false); @@ -181,9 +184,8 @@ public void TestDownloadShutdownTimeWhenInterrupted() var watch = new Stopwatch(); - var downloadGitTask = new DownloadTask(TaskManager.Token, fileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git.zip", - TestBasePath) + var gitLfs = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); + var downloadGitTask = new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath) // An exception is thrown when we stop the task manager // since we're stopping the task manager, no other tasks @@ -207,9 +209,12 @@ public void TestDownloadShutdownTimeWhenInterrupted() TaskManager.Dispose(); evtFinally.WaitOne(); watch.Stop(); + server.Delay = 0; + server.Abort(); exception.Should().NotBeNull(); watch.ElapsedMilliseconds.Should().BeLessThan(250); + } } } diff --git a/src/tests/IntegrationTests/IntegrationTests.csproj b/src/tests/IntegrationTests/IntegrationTests.csproj index cbcbde9d8..c49e24029 100644 --- a/src/tests/IntegrationTests/IntegrationTests.csproj +++ b/src/tests/IntegrationTests/IntegrationTests.csproj @@ -103,6 +103,10 @@ {66a1d219-f61d-4ae4-9bd7-aaeb97276fff} TestUtils + + {3dd3451c-30fa-4294-a3a9-1e080342f867} + TestWebServer + $(SolutionDir)\lib\sfw\sfw.net.dll True diff --git a/src/tests/TestWebServer/HttpServer.cs b/src/tests/TestWebServer/HttpServer.cs new file mode 100644 index 000000000..aa7e85fa2 --- /dev/null +++ b/src/tests/TestWebServer/HttpServer.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +namespace TestWebServer +{ + public class HttpServer + { + private static readonly IDictionary mimeTypeMappings = + new Dictionary(StringComparer.InvariantCultureIgnoreCase) { + { ".gif", "image/gif" }, + { ".html", "text/html" }, + { ".jpg", "image/jpeg" }, + { ".png", "image/png" }, + { ".txt", "text/plain" }, + { ".zip", "application/zip" } + }; + private readonly HttpListener listener; + private readonly string rootDirectory; + private bool abort; + + /// + /// Construct server with given port. + /// + /// Directory path to serve. + /// Port of the server. + public HttpServer(string path = null, int port = 0) + { + if (path == null) + { + path = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), "files"); + } + + rootDirectory = path; + + if (port == 0) + { + //get an empty port + var l = new TcpListener(IPAddress.Loopback, 0); + l.Start(); + port = ((IPEndPoint)l.LocalEndpoint).Port; + l.Stop(); + } + Port = port; + + listener = new HttpListener(); + listener.Prefixes.Add("http://localhost:" + port + "/"); + } + + /// + /// Stop server and dispose all functions. + /// + public void Stop() + { + listener.Stop(); + } + + public void Start() + { + listener.Start(); + while (true) + { + try + { + abort = false; + var context = listener.GetContext(); + Process(context); + } + catch + { + break; + } + } + } + + public void Abort() + { + abort = true; + } + + private void Process(HttpListenerContext context) + { + var filename = context.Request.Url.AbsolutePath; + filename = filename.TrimStart('/'); + filename = Path.Combine(rootDirectory, filename); + + if (!File.Exists(filename)) + { + context.Response.StatusCode = (int)HttpStatusCode.NotFound; + return; + } + + try + { + string mime; + context.Response.ContentType = mimeTypeMappings.TryGetValue(Path.GetExtension(filename), out mime) + ? mime + : "application/octet-stream"; + + context.Response.AddHeader("Date", DateTime.Now.ToString("r")); + context.Response.AddHeader("Last-Modified", File.GetLastWriteTime(filename).ToString("r")); + + using (var input = new FileStream(filename, FileMode.Open)) + { + var length = input.Length; + var range = context.Request.Headers["Range"]; + if (range == null) + { + context.Response.StatusCode = (int)HttpStatusCode.OK; + } + else + { + var parts = range.Split('-'); + var start = long.Parse(parts[0].Substring("bytes=".Length)); + var endRange = parts[1]; + long end = 0; + if (!string.IsNullOrEmpty(endRange)) + { + end = long.Parse(endRange); + } + else + { + end = length - 1; + } + + length = end - start + 1; + + if (input.CanSeek && (input.Length > start) && (end <= input.Length)) + { + context.Response.StatusCode = (int)HttpStatusCode.PartialContent; + context.Response.Headers.Add("Content-Range", $"{start}-{end}/{input.Length}"); + input.Seek(start, SeekOrigin.Current); + } + else + { + context.Response.StatusCode = (int)HttpStatusCode.RequestedRangeNotSatisfiable; + } + } + + if (context.Response.StatusCode != (int)HttpStatusCode.RequestedRangeNotSatisfiable) + { + context.Response.ContentLength64 = length; + + var delay = new ManualResetEvent(false); + Utils.Copy(input, context.Response.OutputStream, length, + progress: (_, __) => + { + if (Delay > 0) + delay.WaitOne(Delay); + return !abort; + }, + progressUpdateRate: 0 + ); + context.Response.OutputStream.Flush(); + } + } + } + catch + { + context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; + } + } + + public int Delay { get; set; } + + public int Port { get; } + } + + static class Utils + { + public static bool Copy(Stream source, Stream destination, long totalSize = 0, int chunkSize = 8192, + Func progress = null, int progressUpdateRate = 100) + { + var buffer = new byte[chunkSize]; + var bytesRead = 0; + long totalRead = 0; + var averageSpeed = -1f; + var lastSpeed = 0f; + var smoothing = 0.005f; + long readLastSecond = 0; + long timeToFinish = 0; + Stopwatch watch = null; + var success = true; + + var trackProgress = (totalSize > 0) && (progress != null); + if (trackProgress) + { + watch = new Stopwatch(); + } + + do + { + if (trackProgress) + { + watch.Start(); + } + + bytesRead = source.Read(buffer, 0, + totalRead + chunkSize > totalSize ? (int)(totalSize - totalRead) : chunkSize); + + if (trackProgress) + { + watch.Stop(); + } + + totalRead += bytesRead; + + if (bytesRead > 0) + { + destination.Write(buffer, 0, bytesRead); + if (trackProgress) + { + readLastSecond += bytesRead; + if ((watch.ElapsedMilliseconds >= progressUpdateRate) || (totalRead == totalSize) || + (bytesRead == 0)) + { + watch.Reset(); + if (bytesRead == 0) // we've reached the end + { + totalSize = totalRead; + } + + lastSpeed = readLastSecond; + readLastSecond = 0; + averageSpeed = averageSpeed < 0f + ? lastSpeed + : smoothing * lastSpeed + (1f - smoothing) * averageSpeed; + timeToFinish = Math.Max(1L, + (long)((totalSize - totalRead) / (averageSpeed / progressUpdateRate))); + + success = progress(totalRead, timeToFinish); + if (!success) + { + break; + } + } + } + else // we still need to call the callback if it's there, so we can abort if needed + { + success = progress?.Invoke(totalRead, timeToFinish) ?? true; + if (!success) + { + break; + } + } + } + } while ((bytesRead > 0) && ((totalSize == 0) || (totalSize > totalRead))); + + if (totalRead > 0) + { + destination.Flush(); + } + + return success; + } + } +} diff --git a/src/tests/TestWebServer/Properties/AssemblyInfo.cs b/src/tests/TestWebServer/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..35d48bfd0 --- /dev/null +++ b/src/tests/TestWebServer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TestWebServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TestWebServer")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3dd3451c-30fa-4294-a3a9-1e080342f867")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/tests/TestWebServer/TestWebServer.csproj b/src/tests/TestWebServer/TestWebServer.csproj new file mode 100644 index 000000000..cac143c1b --- /dev/null +++ b/src/tests/TestWebServer/TestWebServer.csproj @@ -0,0 +1,63 @@ + + + + + Debug + AnyCPU + {3DD3451C-30FA-4294-A3A9-1E080342F867} + Library + Properties + TestWebServer + TestWebServer + v3.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + PreserveNewest + + + + + PreserveNewest + + + + + \ No newline at end of file diff --git a/src/tests/TestWebServer/files/git-lfs.zip b/src/tests/TestWebServer/files/git-lfs.zip new file mode 100644 index 000000000..5a56712a7 --- /dev/null +++ b/src/tests/TestWebServer/files/git-lfs.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a4699fe6028a3727d76b218a10a7e9c6276f097b8ebd782f2e7b3418dacda07 +size 2652291 diff --git a/src/tests/TestWebServer/files/git-lfs.zip.MD5.txt b/src/tests/TestWebServer/files/git-lfs.zip.MD5.txt new file mode 100644 index 000000000..967c3fb8d --- /dev/null +++ b/src/tests/TestWebServer/files/git-lfs.zip.MD5.txt @@ -0,0 +1 @@ +105DF1302560C5F6AA64D1930284C126 \ No newline at end of file From d6acc477b4e42d6a4679185ae09e3bec53275104 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Tue, 30 Jan 2018 13:44:59 +0100 Subject: [PATCH 0120/1008] Need some logging on appveyor --- src/tests/IntegrationTests/SetUpFixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/IntegrationTests/SetUpFixture.cs b/src/tests/IntegrationTests/SetUpFixture.cs index 21c14f375..62793030c 100644 --- a/src/tests/IntegrationTests/SetUpFixture.cs +++ b/src/tests/IntegrationTests/SetUpFixture.cs @@ -14,7 +14,7 @@ public void Setup() Logging.LogAdapter = new MultipleLogAdapter( new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-integration-tests.log") - //, new ConsoleLogAdapter() + , new ConsoleLogAdapter() ); } } From 7989f5b3c1f395f01c92313fe7c33979f98c8c68 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Tue, 30 Jan 2018 14:21:35 +0100 Subject: [PATCH 0121/1008] Make sure tests don't hang. Fix raising finally calls. --- src/GitHub.Api/Tasks/DownloadTask.cs | 30 ++++++- src/GitHub.Api/Tasks/TaskBase.cs | 13 +-- .../Download/DownloadTaskTests.cs | 81 ++++++++++++++----- src/tests/TestWebServer/HttpServer.cs | 30 ++++--- src/tests/TestWebServer/TestWebServer.csproj | 6 ++ 5 files changed, 114 insertions(+), 46 deletions(-) diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 244514924..f627725a8 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -46,6 +46,11 @@ public DownloadTask(CancellationToken token, Name = nameof(DownloadTask); } + protected string BaseRunWithReturn(bool success) + { + return base.RunWithReturn(success); + } + protected override string RunWithReturn(bool success) { var result = base.RunWithReturn(success); @@ -172,10 +177,29 @@ public DownloadTextTask(CancellationToken token, Name = nameof(DownloadTextTask); } - protected override string RunDownload(bool success) + protected override string RunWithReturn(bool success) { - var result = base.RunDownload(success); - return fileSystem.ReadAllText(result, Encoding.UTF8); + var result = BaseRunWithReturn(success); + + RaiseOnStart(); + + try + { + result = RunDownload(success); + result = fileSystem.ReadAllText(result, Encoding.UTF8); + } + catch (Exception ex) + { + Errors = ex.Message; + if (!RaiseFaultHandlers(ex)) + throw; + } + finally + { + RaiseOnEnd(result); + } + + return result; } } } diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index 901d8d3a0..8ef80e2d3 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -321,14 +321,8 @@ protected virtual void RaiseOnStart() protected virtual void RaiseOnEnd() { - var success = Task.Status != TaskStatus.Faulted; - if (success) - { - - } OnEnd?.Invoke(this); - // if it's the last task of the chain and all went well (otherwise finally has been called already) - if (success && continuation == null) + if (continuation == null) finallyHandler?.Invoke(); //Logger.Trace($"Finished {ToString()}"); } @@ -344,8 +338,6 @@ protected virtual bool RaiseFaultHandlers(Exception ex) if (handled) break; } - if (!handled) - finallyHandler?.Invoke(); return handled; } @@ -619,9 +611,8 @@ protected override void RaiseOnStart() protected virtual void RaiseOnEnd(TResult result) { OnEnd?.Invoke(this, result); - if (Task.Status == TaskStatus.Faulted || continuation == null) + if (continuation == null) finallyHandler?.Invoke(result); - RaiseOnEnd(); //Logger.Trace($"Finished {ToString()} {result}"); } diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index be2b50155..b1b6bf24f 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -33,7 +33,7 @@ public override void TestFixtureTearDown() } [Test] - public async Task TestDownloadTask() + public void TestDownloadTask() { Logger.Info("Starting Test: TestDownloadTask"); @@ -42,11 +42,32 @@ public async Task TestDownloadTask() var gitLfs = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); - var md5 = await new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath) - .StartAwait(); + var evtDone = new ManualResetEventSlim(false); - var downloadPath = await new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath) - .StartAwait(); + string md5 = null; + new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath) + .Finally(r => { + md5 = r; + evtDone.Set(); + }) + .Start(); + + evtDone.Wait(10000); + evtDone.Reset(); + Assert.NotNull(md5); + + string downloadPath = null; + new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath) + .Finally(r => { + downloadPath = r; + evtDone.Set(); + }) + .Start(); + + evtDone.Wait(10000); + evtDone.Reset(); + + Assert.NotNull(downloadPath); var md5Sum = fileSystem.CalculateFileMD5(downloadPath); md5Sum.Should().BeEquivalentTo(md5); @@ -58,8 +79,15 @@ public async Task TestDownloadTask() fileSystem.FileDelete(downloadPath); fileSystem.WriteAllBytes(downloadPath, cutDownloadPathBytes); - downloadPath = await new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath) - .StartAwait(); + new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath) + .Finally(r => { + downloadPath = r; + evtDone.Set(); + }) + .Start(); + + evtDone.Wait(10000); + evtDone.Reset(); var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadPath); Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); @@ -90,7 +118,7 @@ public void TestDownloadFailure() downloadTask.Start(); - autoResetEvent.WaitOne(); + autoResetEvent.WaitOne(10000); taskFailed.Should().BeTrue(); exceptionThrown.Should().NotBeNull(); @@ -106,7 +134,17 @@ public void TestDownloadTextTask() var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath); - var result = downloadTask.Start().Result; + + var autoResetEvent = new AutoResetEvent(false); + string result = null; + downloadTask + .Finally(r => { + result = r; + autoResetEvent.Set(); + }) + .Start(); + + autoResetEvent.WaitOne(10000); result.Should().Be("105DF1302560C5F6AA64D1930284C126"); } @@ -120,15 +158,15 @@ public void TestDownloadTextFailure() var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, "https://ggggithub.com/robots.txt"); var exceptionThrown = false; - try - { - var result = downloadTask.Start().Result; - } - catch (Exception e) - { - exceptionThrown = true; - } - + var autoResetEvent = new AutoResetEvent(false); + downloadTask + .Finally((b, exception) => { + exceptionThrown = exception != null; + autoResetEvent.Set(); + }) + .Start(); + + autoResetEvent.WaitOne(10000); exceptionThrown.Should().BeTrue(); } @@ -163,7 +201,7 @@ public void TestDownloadFileAndHash() }) .Start(); - autoResetEvent.WaitOne(); + autoResetEvent.WaitOne(10000); result.Should().BeTrue(); exception.Should().BeNull(); @@ -203,12 +241,13 @@ public void TestDownloadShutdownTimeWhenInterrupted() downloadGitTask.Start(); - evtStop.WaitOne(); + evtStop.WaitOne(10000); watch.Start(); TaskManager.Dispose(); - evtFinally.WaitOne(); + evtFinally.WaitOne(10000); watch.Stop(); + server.Delay = 0; server.Abort(); diff --git a/src/tests/TestWebServer/HttpServer.cs b/src/tests/TestWebServer/HttpServer.cs index aa7e85fa2..a87023a29 100644 --- a/src/tests/TestWebServer/HttpServer.cs +++ b/src/tests/TestWebServer/HttpServer.cs @@ -1,4 +1,5 @@ -using System; +using GitHub.Unity; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -61,20 +62,27 @@ public void Stop() public void Start() { - listener.Start(); - while (true) + try { - try - { - abort = false; - var context = listener.GetContext(); - Process(context); - } - catch + listener.Start(); + while (true) { - break; + try + { + abort = false; + var context = listener.GetContext(); + Process(context); + } + catch + { + break; + } } } + catch (Exception ex) + { + Logging.GetLogger(GetType()).Error(ex); + } } public void Abort() diff --git a/src/tests/TestWebServer/TestWebServer.csproj b/src/tests/TestWebServer/TestWebServer.csproj index cac143c1b..bafa951a4 100644 --- a/src/tests/TestWebServer/TestWebServer.csproj +++ b/src/tests/TestWebServer/TestWebServer.csproj @@ -52,6 +52,12 @@ PreserveNewest + + + {bb6a8eda-15d8-471b-a6ed-ee551e0b3ba0} + GitHub.Logging + + + \ No newline at end of file From c20ac0ad9e46be3475ca789806737f924dd91ab0 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 31 Jan 2018 14:10:05 +0100 Subject: [PATCH 0129/1008] Fix where the test http server serves files from, doh --- src/tests/IntegrationTests/Download/DownloadTaskTests.cs | 2 +- src/tests/TestWebServer/HttpServer.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 0a6a98d1a..d27a3c7ec 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -26,7 +26,7 @@ public override void OnSetup() public override void TestFixtureSetUp() { base.TestFixtureSetUp(); - server = new TestWebServer.HttpServer(); + server = new TestWebServer.HttpServer(SolutionDirectory.Combine("files")); Task.Factory.StartNew(server.Start); ApplicationConfiguration.WebTimeout = 20000; } diff --git a/src/tests/TestWebServer/HttpServer.cs b/src/tests/TestWebServer/HttpServer.cs index afcac094c..a9c44d922 100644 --- a/src/tests/TestWebServer/HttpServer.cs +++ b/src/tests/TestWebServer/HttpServer.cs @@ -67,7 +67,7 @@ public void Start() { try { - Logger.Info($"Starting http server on port {Port}"); + Logger.Info($"Starting http server on port {Port} serving from {rootDirectory}"); listener.Start(); while (true) { From 691257739b750c639053cf068e689e2e6e476a6e Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 31 Jan 2018 14:25:18 +0100 Subject: [PATCH 0130/1008] Lower web request timeout on tests. Rename tests to explain what they are testing --- .../Download/DownloadTaskTests.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index d27a3c7ec..038a6f8ab 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -28,7 +28,7 @@ public override void TestFixtureSetUp() base.TestFixtureSetUp(); server = new TestWebServer.HttpServer(SolutionDirectory.Combine("files")); Task.Factory.StartNew(server.Start); - ApplicationConfiguration.WebTimeout = 20000; + ApplicationConfiguration.WebTimeout = 5000; } public override void TestFixtureTearDown() @@ -60,7 +60,7 @@ private void StopTrackTimeAndLog(Stopwatch watch, ILogging logger) } [Test] - public void TestDownloadTask() + public void ResumingDownloadsWorks() { Stopwatch watch; ILogging logger; @@ -136,7 +136,7 @@ public void TestDownloadTask() } [Test] - public void TestDownloadFailure() + public void DownloadingNonExistingFileThrows() { Stopwatch watch; ILogging logger; @@ -170,7 +170,7 @@ public void TestDownloadFailure() } [Test] - public void TestDownloadTextTask() + public void DownloadingATextFileWorks() { Stopwatch watch; ILogging logger; @@ -200,7 +200,7 @@ public void TestDownloadTextTask() } [Test] - public void TestDownloadTextFailure() + public void DownloadingFromNonExistingDomainThrows() { Stopwatch watch; ILogging logger; @@ -208,7 +208,7 @@ public void TestDownloadTextFailure() var fileSystem = Environment.FileSystem; - var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, "https://ggggithub.com/robots.txt"); + var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, "http://ggggithub.com/robots.txt"); var exceptionThrown = false; var autoResetEvent = new AutoResetEvent(false); @@ -228,7 +228,7 @@ public void TestDownloadTextFailure() } [Test] - public void TestDownloadFileAndHash() + public void DownloadingAFileWithHashValidationWorks() { Stopwatch watch; ILogging logger; @@ -269,7 +269,7 @@ public void TestDownloadFileAndHash() } [Test] - public void TestDownloadShutdownTimeWhenInterrupted() + public void ShutdownTimeWhenTaskManagerDisposed() { Stopwatch watch; ILogging logger; From 1cc4800ccae9bc2870e2e99489d09154f77502d3 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 31 Jan 2018 18:40:42 +0100 Subject: [PATCH 0131/1008] Set namespace of GitHub.Logging to match assembly name, rename Logging class to LogHelper to avoid conflicts --- script | 2 +- src/GitHub.Api/Application/ApiClient.cs | 4 +-- .../Application/ApplicationManagerBase.cs | 6 ++--- src/GitHub.Api/Authentication/Keychain.cs | 4 +-- src/GitHub.Api/Authentication/LoginManager.cs | 4 +-- src/GitHub.Api/Events/RepositoryWatcher.cs | 4 +-- src/GitHub.Api/Git/GitClient.cs | 4 +-- src/GitHub.Api/Git/GitCredentialManager.cs | 4 +-- src/GitHub.Api/Git/Repository.cs | 6 ++--- src/GitHub.Api/Git/RepositoryManager.cs | 4 +-- src/GitHub.Api/IO/Utils.cs | 4 +-- src/GitHub.Api/Installer/GitInstaller.cs | 4 +-- src/GitHub.Api/Metrics/UsageTracker.cs | 4 +-- .../OutputProcessors/ProcessManager.cs | 4 +-- src/GitHub.Api/Platform/DefaultEnvironment.cs | 4 +-- src/GitHub.Api/Platform/ProcessEnvironment.cs | 4 +-- src/GitHub.Api/Platform/Settings.cs | 4 +-- src/GitHub.Api/Tasks/BaseOutputProcessor.cs | 4 +-- .../Tasks/ConcurrentExclusiveInterleave.cs | 2 +- src/GitHub.Api/Tasks/ProcessTask.cs | 4 +-- src/GitHub.Api/Tasks/TaskBase.cs | 4 +-- src/GitHub.Api/Tasks/TaskExtensions.cs | 10 +++---- src/GitHub.Api/Tasks/TaskManager.cs | 4 +-- src/GitHub.Api/UI/TreeBase.cs | 4 +-- src/GitHub.Logging/ConsoleLogAdapter.cs | 2 +- .../Extensions/ExceptionExtensions.cs | 4 +-- src/GitHub.Logging/FileLogAdapter.cs | 2 +- src/GitHub.Logging/GitHub.Logging.csproj | 5 ++-- src/GitHub.Logging/ILogging.cs | 2 +- src/GitHub.Logging/LogAdapterBase.cs | 2 +- src/GitHub.Logging/LogFacade.cs | 22 +++++++-------- .../{Logging.cs => LogHelper.cs} | 27 ++----------------- src/GitHub.Logging/MultipleLogAdapter.cs | 2 +- src/GitHub.Logging/NullLogAdapter.cs | 25 +++++++++++++++++ .../Editor/GitHub.Unity/ApplicationCache.cs | 4 +-- .../Editor/GitHub.Unity/CacheContainer.cs | 4 +-- .../Assets/Editor/GitHub.Unity/EntryPoint.cs | 10 +++---- .../GitHub.Unity/Logging/UnityLogAdapter.cs | 2 +- .../Editor/GitHub.Unity/Misc/Installer.cs | 4 +-- .../Editor/GitHub.Unity/Misc/Utility.cs | 4 +-- .../GitHub.Unity/ScriptObjectSingleton.cs | 8 +++--- .../Editor/GitHub.Unity/UI/BaseWindow.cs | 4 +-- .../GitHub.Unity/UI/ProjectWindowInterface.cs | 4 +-- .../Editor/GitHub.Unity/UI/SettingsView.cs | 6 ++--- .../Assets/Editor/GitHub.Unity/UI/Subview.cs | 4 +-- .../IntegrationTests/BaseIntegrationTest.cs | 4 +-- .../Download/DownloadTaskTests.cs | 4 +-- .../Events/RepositoryWatcherTests.cs | 4 +-- .../IntegrationTestEnvironment.cs | 4 +-- src/tests/IntegrationTests/SetUpFixture.cs | 6 ++--- .../ThreadSynchronizationContext.cs | 4 +-- src/tests/TaskSystemIntegrationTests/Tests.cs | 8 +++--- .../ThreadSynchronizationContext.cs | 4 +-- .../TestUtils/Events/IRepositoryListener.cs | 2 +- .../Events/IRepositoryManagerListener.cs | 4 +-- .../Substitutes/SubstituteFactory.cs | 6 ++--- src/tests/TestWebServer/HttpServer.cs | 7 +++-- src/tests/UnitTests/SetUpFixture.cs | 6 ++--- 58 files changed, 157 insertions(+), 155 deletions(-) rename src/GitHub.Logging/{Logging.cs => LogHelper.cs} (85%) create mode 100644 src/GitHub.Logging/NullLogAdapter.cs diff --git a/script b/script index 4991e35b1..83a155ea9 160000 --- a/script +++ b/script @@ -1 +1 @@ -Subproject commit 4991e35b17d97efb33ce5f33ec3d91ce14cdba8a +Subproject commit 83a155ea9248f2f68c5b20b9705dbe01f94824dc diff --git a/src/GitHub.Api/Application/ApiClient.cs b/src/GitHub.Api/Application/ApiClient.cs index 56ac62765..d13512900 100644 --- a/src/GitHub.Api/Application/ApiClient.cs +++ b/src/GitHub.Api/Application/ApiClient.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Octokit; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace GitHub.Unity { @@ -20,7 +20,7 @@ public static IApiClient Create(UriString repositoryUrl, IKeychain keychain) new GitHubClient(ApplicationConfiguration.ProductHeader, credentialStore, hostAddress.ApiUri)); } - private static readonly ILogging logger = Logging.GetLogger(); + private static readonly ILogging logger = LogHelper.GetLogger(); public HostAddress HostAddress { get; } public UriString OriginalUrl { get; } diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index e6667096e..afbc671e2 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -3,13 +3,13 @@ using System.Threading; using System.Threading.Tasks; using System.Collections.Generic; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace GitHub.Unity { abstract class ApplicationManagerBase : IApplicationManager { - protected static ILogging Logger { get; } = Logging.GetLogger(); + protected static ILogging Logger { get; } = LogHelper.GetLogger(); private RepositoryManager repositoryManager; @@ -36,7 +36,7 @@ protected void Initialize() LocalSettings.Initialize(); SystemSettings.Initialize(); - Logging.TracingEnabled = UserSettings.Get(Constants.TraceLoggingKey, false); + LogHelper.TracingEnabled = UserSettings.Get(Constants.TraceLoggingKey, false); ProcessManager = new ProcessManager(Environment, Platform.GitEnvironment, CancellationToken); Platform.Initialize(ProcessManager, TaskManager); GitClient = new GitClient(Environment, ProcessManager, TaskManager.Token); diff --git a/src/GitHub.Api/Authentication/Keychain.cs b/src/GitHub.Api/Authentication/Keychain.cs index 45d052c02..696e5a136 100644 --- a/src/GitHub.Api/Authentication/Keychain.cs +++ b/src/GitHub.Api/Authentication/Keychain.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Octokit; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace GitHub.Unity { @@ -23,7 +23,7 @@ class Keychain : IKeychain { const string ConnectionFile = "connections.json"; - private readonly ILogging logger = Logging.GetLogger(); + private readonly ILogging logger = LogHelper.GetLogger(); private readonly ICredentialManager credentialManager; private readonly NPath cachePath; diff --git a/src/GitHub.Api/Authentication/LoginManager.cs b/src/GitHub.Api/Authentication/LoginManager.cs index 0ac847342..b87b2222f 100644 --- a/src/GitHub.Api/Authentication/LoginManager.cs +++ b/src/GitHub.Api/Authentication/LoginManager.cs @@ -2,7 +2,7 @@ using System.Net; using System.Threading.Tasks; using Octokit; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace GitHub.Unity { @@ -20,7 +20,7 @@ public enum LoginResultCodes /// class LoginManager : ILoginManager { - private readonly ILogging logger = Logging.GetLogger(); + private readonly ILogging logger = LogHelper.GetLogger(); private readonly string[] scopes = { "user", "repo", "gist", "write:public_key" }; private readonly IKeychain keychain; diff --git a/src/GitHub.Api/Events/RepositoryWatcher.cs b/src/GitHub.Api/Events/RepositoryWatcher.cs index 3e302e06b..dda8bc880 100644 --- a/src/GitHub.Api/Events/RepositoryWatcher.cs +++ b/src/GitHub.Api/Events/RepositoryWatcher.cs @@ -4,7 +4,7 @@ using System.Threading; using System.Threading.Tasks; using sfw.net; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace GitHub.Unity { @@ -294,7 +294,7 @@ public void Dispose() Dispose(true); } - protected static ILogging Logger { get; } = Logging.GetLogger(); + protected static ILogging Logger { get; } = LogHelper.GetLogger(); private enum EventType { diff --git a/src/GitHub.Api/Git/GitClient.cs b/src/GitHub.Api/Git/GitClient.cs index 04602cb59..62c39b717 100644 --- a/src/GitHub.Api/Git/GitClient.cs +++ b/src/GitHub.Api/Git/GitClient.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Generic; using System.Linq; @@ -402,7 +402,7 @@ public ITask Unlock(string file, bool force, .Configure(processManager); } - protected static ILogging Logger { get; } = Logging.GetLogger(); + protected static ILogging Logger { get; } = LogHelper.GetLogger(); } public struct GitUser diff --git a/src/GitHub.Api/Git/GitCredentialManager.cs b/src/GitHub.Api/Git/GitCredentialManager.cs index 7a3cebe58..08ee73877 100644 --- a/src/GitHub.Api/Git/GitCredentialManager.cs +++ b/src/GitHub.Api/Git/GitCredentialManager.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Generic; using System.Threading.Tasks; @@ -7,7 +7,7 @@ namespace GitHub.Unity { class GitCredentialManager : ICredentialManager { - private static ILogging Logger { get; } = Logging.GetLogger(); + private static ILogging Logger { get; } = LogHelper.GetLogger(); private ICredential credential; private string credHelper = null; diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 53a14fdf1..b1f55b0ab 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Generic; using System.Diagnostics; @@ -626,7 +626,7 @@ public bool IsGitHub "{0} Owner: {1} Name: {2} CloneUrl: {3} LocalPath: {4} Branch: {5} Remote: {6}", GetHashCode(), Owner, Name, CloneUrl, LocalPath, CurrentBranch, CurrentRemote); - protected static ILogging Logger { get; } = Logging.GetLogger(); + protected static ILogging Logger { get; } = LogHelper.GetLogger(); } public interface IUser @@ -751,7 +751,7 @@ private void UpdateUserAndEmail() }).Start(); } - protected static ILogging Logger { get; } = Logging.GetLogger(); + protected static ILogging Logger { get; } = LogHelper.GetLogger(); } [Serializable] diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index 396cccd6d..5f4870e7b 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -4,7 +4,7 @@ using System.Threading; using System.Threading.Tasks; using Octokit; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace GitHub.Unity { @@ -595,6 +595,6 @@ private set } } - protected static ILogging Logger { get; } = Logging.GetLogger(); + protected static ILogging Logger { get; } = LogHelper.GetLogger(); } } diff --git a/src/GitHub.Api/IO/Utils.cs b/src/GitHub.Api/IO/Utils.cs index d8262421c..2c0621906 100644 --- a/src/GitHub.Api/IO/Utils.cs +++ b/src/GitHub.Api/IO/Utils.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Diagnostics; using System.IO; @@ -14,7 +14,7 @@ public static bool Copy(Stream source, Stream destination, Func progress = null, int progressUpdateRate = 100) { - var logger = Logging.GetLogger("Copy"); + var logger = LogHelper.GetLogger("Copy"); byte[] buffer = new byte[chunkSize]; int bytesRead = 0; long totalRead = 0; diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index b2e92edad..2d5f6c92d 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Threading; @@ -60,7 +60,7 @@ public NPath GetGitLfsExecPath(NPath gitInstallRoot) class GitInstaller { - private static ILogging Logger = Logging.GetLogger(); + private static ILogging Logger = LogHelper.GetLogger(); private readonly IEnvironment environment; private readonly IZipHelper sharpZipLibHelper; diff --git a/src/GitHub.Api/Metrics/UsageTracker.cs b/src/GitHub.Api/Metrics/UsageTracker.cs index 5b5cff7df..e6a46ed1b 100644 --- a/src/GitHub.Api/Metrics/UsageTracker.cs +++ b/src/GitHub.Api/Metrics/UsageTracker.cs @@ -6,13 +6,13 @@ using System.Globalization; using System.Threading; using Timer = System.Threading.Timer; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace GitHub.Unity { class UsageTracker : IUsageTracker { - private static ILogging Logger { get; } = Logging.GetLogger(); + private static ILogging Logger { get; } = LogHelper.GetLogger(); private static IMetricsService metricsService; private readonly NPath storePath; diff --git a/src/GitHub.Api/OutputProcessors/ProcessManager.cs b/src/GitHub.Api/OutputProcessors/ProcessManager.cs index 5eccb4891..994e88101 100644 --- a/src/GitHub.Api/OutputProcessors/ProcessManager.cs +++ b/src/GitHub.Api/OutputProcessors/ProcessManager.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Diagnostics; using System.IO; @@ -10,7 +10,7 @@ namespace GitHub.Unity { class ProcessManager : IProcessManager { - private static readonly ILogging logger = Logging.GetLogger(); + private static readonly ILogging logger = LogHelper.GetLogger(); private readonly IEnvironment environment; private readonly IProcessEnvironment gitEnvironment; diff --git a/src/GitHub.Api/Platform/DefaultEnvironment.cs b/src/GitHub.Api/Platform/DefaultEnvironment.cs index 2c7e6563f..5536e93a0 100644 --- a/src/GitHub.Api/Platform/DefaultEnvironment.cs +++ b/src/GitHub.Api/Platform/DefaultEnvironment.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.IO; using System.Linq; @@ -190,6 +190,6 @@ public static bool OnMac set { onMac = value; } } public string ExecutableExtension { get { return IsWindows ? ".exe" : null; } } - protected static ILogging Logger { get; } = Logging.GetLogger(); + protected static ILogging Logger { get; } = LogHelper.GetLogger(); } } \ No newline at end of file diff --git a/src/GitHub.Api/Platform/ProcessEnvironment.cs b/src/GitHub.Api/Platform/ProcessEnvironment.cs index c21736b5f..43d7a923c 100644 --- a/src/GitHub.Api/Platform/ProcessEnvironment.cs +++ b/src/GitHub.Api/Platform/ProcessEnvironment.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Diagnostics; using System.Globalization; @@ -13,7 +13,7 @@ class ProcessEnvironment : IProcessEnvironment public ProcessEnvironment(IEnvironment environment) { - Logger = Logging.GetLogger(GetType()); + Logger = LogHelper.GetLogger(GetType()); Environment = environment; } diff --git a/src/GitHub.Api/Platform/Settings.cs b/src/GitHub.Api/Platform/Settings.cs index 1f40b89db..8f622cf3a 100644 --- a/src/GitHub.Api/Platform/Settings.cs +++ b/src/GitHub.Api/Platform/Settings.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Generic; using System.IO; @@ -34,7 +34,7 @@ class JsonBackedSettings : BaseSettings public JsonBackedSettings() { - logger = Logging.GetLogger(GetType()); + logger = LogHelper.GetLogger(GetType()); fileExists = (path) => File.Exists(path); readAllText = (path, encoding) => File.ReadAllText(path, encoding); writeAllText = (path, content) => File.WriteAllText(path, content); diff --git a/src/GitHub.Api/Tasks/BaseOutputProcessor.cs b/src/GitHub.Api/Tasks/BaseOutputProcessor.cs index 1a5bb4201..1303bafb9 100644 --- a/src/GitHub.Api/Tasks/BaseOutputProcessor.cs +++ b/src/GitHub.Api/Tasks/BaseOutputProcessor.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Generic; using System.Text; @@ -34,7 +34,7 @@ protected void RaiseOnEntry(T entry) public virtual T Result { get; protected set; } private ILogging logger; - protected ILogging Logger { get { return logger = logger ?? Logging.GetLogger(GetType()); } } + protected ILogging Logger { get { return logger = logger ?? LogHelper.GetLogger(GetType()); } } } public abstract class BaseOutputProcessor : BaseOutputProcessor, IOutputProcessor diff --git a/src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs b/src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs index 37982e141..8d14887f4 100644 --- a/src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs +++ b/src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs @@ -399,7 +399,7 @@ internal void ExecuteTask(Task task) //} //catch(Exception ex) //{ - // Logging.Error(ex); + // LogHelper.Error(ex); // throw; //} diff --git a/src/GitHub.Api/Tasks/ProcessTask.cs b/src/GitHub.Api/Tasks/ProcessTask.cs index 8f1b0d9f6..f02821999 100644 --- a/src/GitHub.Api/Tasks/ProcessTask.cs +++ b/src/GitHub.Api/Tasks/ProcessTask.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Generic; using System.ComponentModel; @@ -65,7 +65,7 @@ class ProcessWrapper public StreamWriter Input { get; private set; } private ILogging logger; - protected ILogging Logger { get { return logger = logger ?? Logging.GetLogger(GetType()); } } + protected ILogging Logger { get { return logger = logger ?? LogHelper.GetLogger(GetType()); } } public ProcessWrapper(Process process, IOutputProcessor outputProcessor, Action onStart, Action onEnd, Action onError, diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index 5b2407d4f..5472bdeef 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Threading; using System.Threading.Tasks; @@ -398,7 +398,7 @@ public override string ToString() public string Name { get; set; } public virtual TaskAffinity Affinity { get; set; } private ILogging logger; - protected ILogging Logger { get { return logger = logger ?? Logging.GetLogger(GetType()); } } + protected ILogging Logger { get { return logger = logger ?? LogHelper.GetLogger(GetType()); } } public TaskBase DependsOn { get; private set; } public CancellationToken Token { get; } internal TaskBase Continuation => continuation; diff --git a/src/GitHub.Api/Tasks/TaskExtensions.cs b/src/GitHub.Api/Tasks/TaskExtensions.cs index 2521beee0..71e0f9201 100644 --- a/src/GitHub.Api/Tasks/TaskExtensions.cs +++ b/src/GitHub.Api/Tasks/TaskExtensions.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Threading; using System.Threading.Tasks; @@ -34,7 +34,7 @@ public static async Task SafeAwait(this Task source, Action handler = } catch (Exception ex) { - Logging.GetLogger().Error(ex); + LogHelper.GetLogger().Error(ex); if (handler == null) throw; handler(ex); @@ -49,7 +49,7 @@ public static async Task SafeAwait(this Task source, Func } catch (Exception ex) { - Logging.GetLogger().Error(ex); + LogHelper.GetLogger().Error(ex); if (handler == null) throw; return handler(ex); @@ -64,7 +64,7 @@ public static async Task StartAwait(this ITask source, Action handler } catch (Exception ex) { - Logging.GetLogger().Error(ex); + LogHelper.GetLogger().Error(ex); if (handler == null) throw; handler(ex); @@ -79,7 +79,7 @@ public static async Task StartAwait(this ITask source, Func(); + private static readonly ILogging logger = LogHelper.GetLogger(); private CancellationTokenSource cts; private readonly ConcurrentExclusiveInterleave manager; diff --git a/src/GitHub.Api/UI/TreeBase.cs b/src/GitHub.Api/UI/TreeBase.cs index 36677a6ec..fecf2063f 100644 --- a/src/GitHub.Api/UI/TreeBase.cs +++ b/src/GitHub.Api/UI/TreeBase.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Generic; using System.Linq; @@ -31,7 +31,7 @@ public abstract class TreeBase where TNode : class, ITreeNode wher protected TreeBase() { - Logger = Logging.GetLogger(GetType()); + Logger = LogHelper.GetLogger(GetType()); } public abstract IEnumerable GetCheckedFiles(); diff --git a/src/GitHub.Logging/ConsoleLogAdapter.cs b/src/GitHub.Logging/ConsoleLogAdapter.cs index 0102178f5..4fc945c36 100644 --- a/src/GitHub.Logging/ConsoleLogAdapter.cs +++ b/src/GitHub.Logging/ConsoleLogAdapter.cs @@ -1,7 +1,7 @@ using System; using System.Threading; -namespace GitHub.Unity.Logs +namespace GitHub.Logging { class ConsoleLogAdapter : LogAdapterBase { diff --git a/src/GitHub.Logging/Extensions/ExceptionExtensions.cs b/src/GitHub.Logging/Extensions/ExceptionExtensions.cs index db9d235e7..91879ea53 100644 --- a/src/GitHub.Logging/Extensions/ExceptionExtensions.cs +++ b/src/GitHub.Logging/Extensions/ExceptionExtensions.cs @@ -1,7 +1,7 @@ using System; using System.Linq; -namespace GitHub.Unity.Logs +namespace GitHub.Logging { static class ExceptionExtensions { @@ -17,7 +17,7 @@ public static string GetExceptionMessage(this Exception ex) var caller = Environment.StackTrace; var stack = caller.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); message += Environment.NewLine + "======="; - message += Environment.NewLine + String.Join(Environment.NewLine, stack.Skip(1).SkipWhile(x => x.Contains("GitHub.Unity.Logs")).ToArray()); + message += Environment.NewLine + String.Join(Environment.NewLine, stack.Skip(1).SkipWhile(x => x.Contains("GitHub.Logging")).ToArray()); return message; } } diff --git a/src/GitHub.Logging/FileLogAdapter.cs b/src/GitHub.Logging/FileLogAdapter.cs index a3f5290a5..693dbc296 100644 --- a/src/GitHub.Logging/FileLogAdapter.cs +++ b/src/GitHub.Logging/FileLogAdapter.cs @@ -2,7 +2,7 @@ using System.IO; using System.Threading; -namespace GitHub.Unity.Logs +namespace GitHub.Logging { class FileLogAdapter : LogAdapterBase { diff --git a/src/GitHub.Logging/GitHub.Logging.csproj b/src/GitHub.Logging/GitHub.Logging.csproj index 2f52b9f73..f0d7cb00f 100644 --- a/src/GitHub.Logging/GitHub.Logging.csproj +++ b/src/GitHub.Logging/GitHub.Logging.csproj @@ -7,7 +7,7 @@ {BB6A8EDA-15D8-471B-A6ED-EE551E0B3BA0} Library Properties - GitHub.Unity + GitHub.Logging GitHub.Logging v3.5 512 @@ -62,8 +62,9 @@ - + + Properties\SolutionInfo.cs diff --git a/src/GitHub.Logging/ILogging.cs b/src/GitHub.Logging/ILogging.cs index b0d28203c..94d3550b8 100644 --- a/src/GitHub.Logging/ILogging.cs +++ b/src/GitHub.Logging/ILogging.cs @@ -1,6 +1,6 @@ using System; -namespace GitHub.Unity.Logs +namespace GitHub.Logging { public interface ILogging { diff --git a/src/GitHub.Logging/LogAdapterBase.cs b/src/GitHub.Logging/LogAdapterBase.cs index a7aaf61cc..4970d32db 100644 --- a/src/GitHub.Logging/LogAdapterBase.cs +++ b/src/GitHub.Logging/LogAdapterBase.cs @@ -1,4 +1,4 @@ -namespace GitHub.Unity.Logs +namespace GitHub.Logging { public abstract class LogAdapterBase { diff --git a/src/GitHub.Logging/LogFacade.cs b/src/GitHub.Logging/LogFacade.cs index 21a482a95..ae6bb29e6 100644 --- a/src/GitHub.Logging/LogFacade.cs +++ b/src/GitHub.Logging/LogFacade.cs @@ -1,6 +1,6 @@ using System; -namespace GitHub.Unity.Logs +namespace GitHub.Logging { class LogFacade : ILogging { @@ -13,20 +13,20 @@ public LogFacade(string context) public void Info(string message) { - Logging.LogAdapter.Info(context, message); + LogHelper.LogAdapter.Info(context, message); } public void Debug(string message) { #if DEBUG - Logging.LogAdapter.Debug(context, message); + LogHelper.LogAdapter.Debug(context, message); #endif } public void Trace(string message) { - if (!Logging.TracingEnabled) return; - Logging.LogAdapter.Trace(context, message); + if (!LogHelper.TracingEnabled) return; + LogHelper.LogAdapter.Trace(context, message); } public void Info(string format, params object[] objects) @@ -79,35 +79,35 @@ public void Debug(Exception ex, string format, params object[] objects) public void Trace(string format, params object[] objects) { - if (!Logging.TracingEnabled) return; + if (!LogHelper.TracingEnabled) return; Trace(String.Format(format, objects)); } public void Trace(Exception ex, string message) { - if (!Logging.TracingEnabled) return; + if (!LogHelper.TracingEnabled) return; Trace(String.Concat(message, Environment.NewLine, ex.GetExceptionMessage())); } public void Trace(Exception ex) { - if (!Logging.TracingEnabled) return; + if (!LogHelper.TracingEnabled) return; Trace(ex, string.Empty); } public void Trace(Exception ex, string format, params object[] objects) { - if (!Logging.TracingEnabled) return; + if (!LogHelper.TracingEnabled) return; Trace(ex, String.Format(format, objects)); } public void Warning(string message) { - Logging.LogAdapter.Warning(context, message); + LogHelper.LogAdapter.Warning(context, message); } public void Warning(string format, params object[] objects) @@ -132,7 +132,7 @@ public void Warning(Exception ex, string format, params object[] objects) public void Error(string message) { - Logging.LogAdapter.Error(context, message); + LogHelper.LogAdapter.Error(context, message); } public void Error(string format, params object[] objects) diff --git a/src/GitHub.Logging/Logging.cs b/src/GitHub.Logging/LogHelper.cs similarity index 85% rename from src/GitHub.Logging/Logging.cs rename to src/GitHub.Logging/LogHelper.cs index d8948ea08..c2709817f 100644 --- a/src/GitHub.Logging/Logging.cs +++ b/src/GitHub.Logging/LogHelper.cs @@ -1,31 +1,8 @@ using System; -namespace GitHub.Unity.Logs +namespace GitHub.Logging { - class NullLogAdapter : LogAdapterBase - { - public override void Info(string context, string message) - { - } - - public override void Debug(string context, string message) - { - } - - public override void Trace(string context, string message) - { - } - - public override void Warning(string context, string message) - { - } - - public override void Error(string context, string message) - { - } - } - - public static class Logging + public static class LogHelper { private static readonly LogAdapterBase nullLogAdapter = new NullLogAdapter(); diff --git a/src/GitHub.Logging/MultipleLogAdapter.cs b/src/GitHub.Logging/MultipleLogAdapter.cs index 6bf138eff..f9daf572a 100644 --- a/src/GitHub.Logging/MultipleLogAdapter.cs +++ b/src/GitHub.Logging/MultipleLogAdapter.cs @@ -1,4 +1,4 @@ -namespace GitHub.Unity.Logs +namespace GitHub.Logging { class MultipleLogAdapter : LogAdapterBase { diff --git a/src/GitHub.Logging/NullLogAdapter.cs b/src/GitHub.Logging/NullLogAdapter.cs new file mode 100644 index 000000000..3d0e78724 --- /dev/null +++ b/src/GitHub.Logging/NullLogAdapter.cs @@ -0,0 +1,25 @@ +namespace GitHub.Logging +{ + class NullLogAdapter : LogAdapterBase + { + public override void Info(string context, string message) + { + } + + public override void Debug(string context, string message) + { + } + + public override void Trace(string context, string message) + { + } + + public override void Warning(string context, string message) + { + } + + public override void Error(string context, string message) + { + } + } +} \ No newline at end of file diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs index d6a660336..48c5ef111 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Generic; using System.Globalization; @@ -128,7 +128,7 @@ abstract class ManagedCacheBase : ScriptObjectSingleton where T : Scriptab protected ManagedCacheBase(bool invalidOnFirstRun) { this.invalidOnFirstRun = invalidOnFirstRun; - Logger = Logging.GetLogger(GetType()); + Logger = LogHelper.GetLogger(GetType()); } public void ValidateData() diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/CacheContainer.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/CacheContainer.cs index 90fd3485e..e97090963 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/CacheContainer.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/CacheContainer.cs @@ -1,11 +1,11 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; namespace GitHub.Unity { public class CacheContainer : ICacheContainer { - private static ILogging Logger = Logging.GetLogger(); + private static ILogging Logger = LogHelper.GetLogger(); private IRepositoryInfoCache repositoryInfoCache; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs index fbb375359..3b25a5277 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.IO; using System.Net; @@ -22,7 +22,7 @@ static EntryPoint() return; } - Logging.LogAdapter = new FileLogAdapter(tempEnv.LogPath); + LogHelper.LogAdapter = new FileLogAdapter(tempEnv.LogPath); ServicePointManager.ServerCertificateValidationCallback = ServerCertificateValidationCallback; EditorApplication.update += Initialize; @@ -56,14 +56,14 @@ private static void Initialize() } catch (Exception ex) { - Logging.Error(ex, "Error rotating log files"); + LogHelper.Error(ex, "Error rotating log files"); } Debug.LogFormat("Initialized GitHub for Unity version {0}{1}Log file: {2}", ApplicationInfo.Version, Environment.NewLine, logPath); } - Logging.LogAdapter = new FileLogAdapter(logPath); - Logging.Info("Initializing GitHub for Unity version " + ApplicationInfo.Version); + LogHelper.LogAdapter = new FileLogAdapter(logPath); + LogHelper.Info("Initializing GitHub for Unity version " + ApplicationInfo.Version); ApplicationManager.Run(ApplicationCache.Instance.FirstRun); } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Logging/UnityLogAdapter.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Logging/UnityLogAdapter.cs index dae0ef4f8..db256a976 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Logging/UnityLogAdapter.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Logging/UnityLogAdapter.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Threading; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Installer.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Installer.cs index 99e1707f6..6b6ef8ba0 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Installer.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Installer.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using UnityEditor; using UnityEngine; @@ -7,7 +7,7 @@ namespace GitHub.Unity { class Installer : ScriptableObject { - private static readonly ILogging logger = Logging.GetLogger(); + private static readonly ILogging logger = LogHelper.GetLogger(); private const string PackageName = "GitHub extensions"; private const string QueryTitle = "Embed " + PackageName + "?"; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs index e02fa979d..91f2a9400 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.IO; using System.Linq; @@ -94,7 +94,7 @@ static StreamExtensions() if (loadImage == null) { - Logging.Error("Could not find ImageConversion.LoadImage method"); + LogHelper.Error("Could not find ImageConversion.LoadImage method"); } } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs index 0ca405723..3273cc472 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ScriptObjectSingleton.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Linq; using UnityEditorInternal; @@ -66,7 +66,7 @@ protected ScriptObjectSingleton() { if (instance != null) { - Logging.Instance.Error("Singleton already exists!"); + LogHelper.Instance.Error("Singleton already exists!"); } else { @@ -99,7 +99,7 @@ protected virtual void Save(bool saveAsText) { if (instance == null) { - Logging.Instance.Error("Cannot save singleton, no instance!"); + LogHelper.Instance.Error("Cannot save singleton, no instance!"); return; } @@ -116,7 +116,7 @@ private static NPath GetFilePath() var attr = typeof(T).GetCustomAttributes(true) .Select(t => t as LocationAttribute) .FirstOrDefault(t => t != null); - //Logging.Instance.Debug("FilePath {0}", attr != null ? attr.filepath : null); + //LogHelper.Instance.Debug("FilePath {0}", attr != null ? attr.filepath : null); return attr != null ? attr.filepath.ToNPath() : null; } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BaseWindow.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BaseWindow.cs index 1ff48d743..fa47081e5 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BaseWindow.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BaseWindow.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using UnityEditor; using UnityEngine; @@ -135,7 +135,7 @@ protected ILogging Logger get { if (logger == null) - logger = Logging.GetLogger(GetType()); + logger = LogHelper.GetLogger(GetType()); return logger; } } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ProjectWindowInterface.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ProjectWindowInterface.cs index 58f031488..4a4198b2e 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ProjectWindowInterface.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ProjectWindowInterface.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Generic; using System.Linq; @@ -19,7 +19,7 @@ class ProjectWindowInterface : AssetPostprocessor private static IRepository repository; private static bool isBusy = false; private static ILogging logger; - private static ILogging Logger { get { return logger = logger ?? Logging.GetLogger(); } } + private static ILogging Logger { get { return logger = logger ?? LogHelper.GetLogger(); } } private static CacheUpdateEvent lastRepositoryStatusChangedEvent; private static CacheUpdateEvent lastLocksChangedEvent; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/SettingsView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/SettingsView.cs index 015ab2282..eb518feae 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/SettingsView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/SettingsView.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Generic; using System.Linq; @@ -326,7 +326,7 @@ private void OnLoggingSettingsGui() EditorGUI.BeginDisabledGroup(IsBusy); { - var traceLogging = Logging.TracingEnabled; + var traceLogging = LogHelper.TracingEnabled; EditorGUI.BeginChangeCheck(); { @@ -334,7 +334,7 @@ private void OnLoggingSettingsGui() } if (EditorGUI.EndChangeCheck()) { - Logging.TracingEnabled = traceLogging; + LogHelper.TracingEnabled = traceLogging; Manager.UserSettings.Set(Constants.TraceLoggingKey, traceLogging); } } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Subview.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Subview.cs index 23d3a43fb..7678f4613 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Subview.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Subview.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using UnityEngine; @@ -75,7 +75,7 @@ protected ILogging Logger get { if (logger == null) - logger = Logging.GetLogger(GetType()); + logger = LogHelper.GetLogger(GetType()); return logger; } } diff --git a/src/tests/IntegrationTests/BaseIntegrationTest.cs b/src/tests/IntegrationTests/BaseIntegrationTest.cs index 62b3f05d7..87091f6dd 100644 --- a/src/tests/IntegrationTests/BaseIntegrationTest.cs +++ b/src/tests/IntegrationTests/BaseIntegrationTest.cs @@ -5,7 +5,7 @@ using NCrunch.Framework; using System.Threading; using NSubstitute; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace IntegrationTests { @@ -39,7 +39,7 @@ protected void InitializeEnvironment(NPath repoPath, [TestFixtureSetUp] public virtual void TestFixtureSetUp() { - Logger = Logging.GetLogger(GetType()); + Logger = LogHelper.GetLogger(GetType()); Factory = new TestUtils.SubstituteFactory(); GitHub.Unity.Guard.InUnitTestRunner = true; } diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index 038a6f8ab..bcf0ac955 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -6,7 +6,7 @@ using GitHub.Unity; using NUnit.Framework; using System.Diagnostics; -using GitHub.Unity.Logs; +using GitHub.Logging; using System.Runtime.CompilerServices; namespace IntegrationTests.Download @@ -41,7 +41,7 @@ public override void TestFixtureTearDown() private void StartTest(out Stopwatch watch, out ILogging logger, [CallerMemberName] string testName = "test") { watch = new Stopwatch(); - logger = Logging.GetLogger(testName); + logger = LogHelper.GetLogger(testName); logger.Trace("Starting test"); } diff --git a/src/tests/IntegrationTests/Events/RepositoryWatcherTests.cs b/src/tests/IntegrationTests/Events/RepositoryWatcherTests.cs index 4271452b8..6a72d1155 100644 --- a/src/tests/IntegrationTests/Events/RepositoryWatcherTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryWatcherTests.cs @@ -6,7 +6,7 @@ using NUnit.Framework; using TestUtils; using System.Threading.Tasks; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace IntegrationTests { @@ -499,7 +499,7 @@ static class RepositoryWatcherListenerExtensions { public static void AttachListener(this IRepositoryWatcherListener listener, IRepositoryWatcher repositoryWatcher, RepositoryWatcherAutoResetEvent autoResetEvent = null, bool trace = false) { - var logger = trace ? Logging.GetLogger() : null; + var logger = trace ? LogHelper.GetLogger() : null; repositoryWatcher.HeadChanged += () => { diff --git a/src/tests/IntegrationTests/IntegrationTestEnvironment.cs b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs index 7517d9e0f..a99d636d1 100644 --- a/src/tests/IntegrationTests/IntegrationTestEnvironment.cs +++ b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs @@ -1,12 +1,12 @@ using System; using GitHub.Unity; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace IntegrationTests { class IntegrationTestEnvironment : IEnvironment { - private static readonly ILogging logger = Logging.GetLogger(); + private static readonly ILogging logger = LogHelper.GetLogger(); private readonly bool enableTrace; private readonly NPath integrationTestEnvironmentPath; diff --git a/src/tests/IntegrationTests/SetUpFixture.cs b/src/tests/IntegrationTests/SetUpFixture.cs index 83aedae69..0dc82d28c 100644 --- a/src/tests/IntegrationTests/SetUpFixture.cs +++ b/src/tests/IntegrationTests/SetUpFixture.cs @@ -1,7 +1,7 @@ using System; using GitHub.Unity; using NUnit.Framework; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace IntegrationTests { @@ -11,9 +11,9 @@ public class SetUpFixture [SetUp] public void Setup() { - Logging.TracingEnabled = true; + LogHelper.TracingEnabled = true; - Logging.LogAdapter = new MultipleLogAdapter( + LogHelper.LogAdapter = new MultipleLogAdapter( new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-integration-tests.log") //, new ConsoleLogAdapter() ); diff --git a/src/tests/IntegrationTests/ThreadSynchronizationContext.cs b/src/tests/IntegrationTests/ThreadSynchronizationContext.cs index 9256ef42d..69da46a98 100644 --- a/src/tests/IntegrationTests/ThreadSynchronizationContext.cs +++ b/src/tests/IntegrationTests/ThreadSynchronizationContext.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -89,7 +89,7 @@ public void Pump() } if (queue.TryDequeue(out data)) { - Logging.GetLogger().Trace($"Running {data.Id} on main thread"); + LogHelper.GetLogger().Trace($"Running {data.Id} on main thread"); data.Run(); } } diff --git a/src/tests/TaskSystemIntegrationTests/Tests.cs b/src/tests/TaskSystemIntegrationTests/Tests.cs index cab5f0c61..44ce4e36d 100644 --- a/src/tests/TaskSystemIntegrationTests/Tests.cs +++ b/src/tests/TaskSystemIntegrationTests/Tests.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks.Schedulers; using System.IO; using NSubstitute; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace IntegrationTests { @@ -16,7 +16,7 @@ class BaseTest { public BaseTest() { - Logger = Logging.GetLogger(GetType()); + Logger = LogHelper.GetLogger(GetType()); } protected ILogging Logger { get; } @@ -31,8 +31,8 @@ public BaseTest() public void OneTimeSetup() { GitHub.Unity.Guard.InUnitTestRunner = true; - Logging.LogAdapter = new MultipleLogAdapter(new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-tasksystem-tests.log")); - //Logging.TracingEnabled = true; + LogHelper.LogAdapter = new MultipleLogAdapter(new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-tasksystem-tests.log")); + //LogHelper.TracingEnabled = true; TaskManager = new TaskManager(); var syncContext = new ThreadSynchronizationContext(Token); TaskManager.UIScheduler = new SynchronizationContextTaskScheduler(syncContext); diff --git a/src/tests/TaskSystemIntegrationTests/ThreadSynchronizationContext.cs b/src/tests/TaskSystemIntegrationTests/ThreadSynchronizationContext.cs index cbd72e1ca..fdcfaed44 100644 --- a/src/tests/TaskSystemIntegrationTests/ThreadSynchronizationContext.cs +++ b/src/tests/TaskSystemIntegrationTests/ThreadSynchronizationContext.cs @@ -1,4 +1,4 @@ -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -90,7 +90,7 @@ public void Pump() } if (queue.TryDequeue(out data)) { - Logging.GetLogger().Trace($"Running {data.Id} on main thread"); + LogHelper.GetLogger().Trace($"Running {data.Id} on main thread"); data.Run(); } } diff --git a/src/tests/TestUtils/Events/IRepositoryListener.cs b/src/tests/TestUtils/Events/IRepositoryListener.cs index c1327ca11..a03e043e3 100644 --- a/src/tests/TestUtils/Events/IRepositoryListener.cs +++ b/src/tests/TestUtils/Events/IRepositoryListener.cs @@ -18,7 +18,7 @@ static class RepositoryListenerExtensions public static void AttachListener(this IRepositoryListener listener, IRepository repository, RepositoryEvents repositoryEvents = null, bool trace = true) { - //var logger = trace ? Logging.GetLogger() : null; + //var logger = trace ? LogHelper.GetLogger() : null; } public static void AssertDidNotReceiveAnyCalls(this IRepositoryListener repositoryListener) diff --git a/src/tests/TestUtils/Events/IRepositoryManagerListener.cs b/src/tests/TestUtils/Events/IRepositoryManagerListener.cs index 644ce6415..f9906fffb 100644 --- a/src/tests/TestUtils/Events/IRepositoryManagerListener.cs +++ b/src/tests/TestUtils/Events/IRepositoryManagerListener.cs @@ -4,7 +4,7 @@ using System.Threading; using GitHub.Unity; using NSubstitute; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace TestUtils.Events { @@ -57,7 +57,7 @@ static class RepositoryManagerListenerExtensions public static void AttachListener(this IRepositoryManagerListener listener, IRepositoryManager repositoryManager, RepositoryManagerEvents managerEvents = null, bool trace = true) { - var logger = trace ? Logging.GetLogger() : null; + var logger = trace ? LogHelper.GetLogger() : null; repositoryManager.IsBusyChanged += isBusy => { logger?.Trace("OnIsBusyChanged: {0}", isBusy); diff --git a/src/tests/TestUtils/Substitutes/SubstituteFactory.cs b/src/tests/TestUtils/Substitutes/SubstituteFactory.cs index 680331c45..8859b764e 100644 --- a/src/tests/TestUtils/Substitutes/SubstituteFactory.cs +++ b/src/tests/TestUtils/Substitutes/SubstituteFactory.cs @@ -6,7 +6,7 @@ using GitHub.Unity; using NSubstitute; using System.Threading; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace TestUtils { @@ -38,7 +38,7 @@ public IFileSystem CreateFileSystem(CreateFileSystemOptions createFileSystemOpti var fileSystem = Substitute.For(); var realFileSystem = new FileSystem(); - var logger = Logging.GetLogger("TestFileSystem"); + var logger = LogHelper.GetLogger("TestFileSystem"); fileSystem.DirectorySeparatorChar.Returns(realFileSystem.DirectorySeparatorChar); fileSystem.GetCurrentDirectory().Returns(createFileSystemOptions.CurrentDirectory); @@ -347,7 +347,7 @@ public IPlatform CreatePlatform() public IGitClient CreateRepositoryProcessRunner( CreateRepositoryProcessRunnerOptions options = null) { - var logger = Logging.GetLogger("TestRepositoryProcessRunner"); + var logger = LogHelper.GetLogger("TestRepositoryProcessRunner"); options = options ?? new CreateRepositoryProcessRunnerOptions(); diff --git a/src/tests/TestWebServer/HttpServer.cs b/src/tests/TestWebServer/HttpServer.cs index a9c44d922..0cd38bb5a 100644 --- a/src/tests/TestWebServer/HttpServer.cs +++ b/src/tests/TestWebServer/HttpServer.cs @@ -1,5 +1,4 @@ -using GitHub.Unity; -using GitHub.Unity.Logs; +using GitHub.Logging; using System; using System.Collections.Generic; using System.Diagnostics; @@ -24,7 +23,7 @@ public class HttpServer private readonly HttpListener listener; private readonly string rootDirectory; private bool abort; - private static ILogging Logger = Logging.GetLogger(); + private static ILogging Logger = LogHelper.GetLogger(); private ManualResetEvent delay = new ManualResetEvent(false); /// @@ -181,7 +180,7 @@ private void Process(HttpListenerContext context) } catch (Exception ex) { - Logging.GetLogger().Error(ex); + LogHelper.GetLogger().Error(ex); context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; } finally diff --git a/src/tests/UnitTests/SetUpFixture.cs b/src/tests/UnitTests/SetUpFixture.cs index 97b4b3511..a10678aa7 100644 --- a/src/tests/UnitTests/SetUpFixture.cs +++ b/src/tests/UnitTests/SetUpFixture.cs @@ -1,7 +1,7 @@ using System; using GitHub.Unity; using NUnit.Framework; -using GitHub.Unity.Logs; +using GitHub.Logging; namespace UnitTests { @@ -11,9 +11,9 @@ public class SetUpFixture [SetUp] public void SetUp() { - Logging.TracingEnabled = true; + LogHelper.TracingEnabled = true; - Logging.LogAdapter = new MultipleLogAdapter( + LogHelper.LogAdapter = new MultipleLogAdapter( new FileLogAdapter($"..\\{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}-unit-tests.log") //, new ConsoleLogAdapter() ); From 3af456196b064af641aae1d1859bddf90cf1c514 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 31 Jan 2018 22:02:43 +0100 Subject: [PATCH 0132/1008] Make it possible to branch out on task success and failure. Cleanups Kill some unused code in the task system, mainly the Defer paths which we aren't using anymore Add a way of calling different tasks depending on the success or failure of the previous task. Add some different ways of setting the result of a task beyond the value returned by the previous task, mainly for seeding initial values. --- .../Application/ApplicationManagerBase.cs | 107 +++++------ src/GitHub.Api/Installer/GitInstaller.cs | 133 ++++++------- src/GitHub.Api/Tasks/ActionTask.cs | 30 ++- src/GitHub.Api/Tasks/TaskBase.cs | 174 ++++++------------ src/GitHub.Api/Tasks/TaskExtensions.cs | 63 ++++--- .../Editor/GitHub.Unity/UI/HistoryView.cs | 2 +- 6 files changed, 225 insertions(+), 284 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index afbc671e2..61894c369 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -47,66 +47,23 @@ public void Run(bool firstRun) { Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory); - var afterGitSetup = new ActionTask(CancellationToken, RestartRepository) - .ThenInUI(InitializeUI); - - //GitClient.GetConfig cannot be called until there is a git path set so it is wrapped in an ActionTask - var windowsCredentialSetup = new ActionTask(CancellationToken, () => { - GitClient.GetConfig("credential.helper", GitConfigSource.Global).Then((b, credentialHelper) => { - if (!string.IsNullOrEmpty(credentialHelper)) - { - Logger.Trace("Windows CredentialHelper: {0}", credentialHelper); - afterGitSetup.Start(); - } - else - { - Logger.Warning("No Windows CredentialHeloper found: Setting to wincred"); - - GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global) - .Then(() => { afterGitSetup.Start(); }).Start(); - } - }).Start(); - }); - - var afterPathDetermined = new ActionTask(CancellationToken, (b, path) => { - Logger.Trace("Setting Environment git path: {0}", path); - Environment.GitExecutablePath = path; - }).ThenInUI(() => { - Environment.User.Initialize(GitClient); - - if (Environment.IsWindows) - { - windowsCredentialSetup.Start(); - } - else - { - afterGitSetup.Start(); - } - }); - - - var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath(); - if (gitExecutablePath != null && gitExecutablePath.FileExists()) + var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath(); + if (gitExecutablePath != null && gitExecutablePath.FileExists()) // we have a git path { Logger.Trace("Using git install path from settings: {0}", gitExecutablePath); - - new FuncTask(CancellationToken, () => gitExecutablePath) - .Then(afterPathDetermined) - .Start(); + InitializeEnvironment(gitExecutablePath); } - else + else // we need to go find git { Logger.Trace("No git path found in settings"); + var initEnvironmentTask = new ActionTask(CancellationToken, (b, path) => InitializeEnvironment(path)) { Affinity = TaskAffinity.UI }; var findExecTask = new FindExecTask("git", CancellationToken) - .Finally((b, ex, path) => { + .FinallyInUI((b, ex, path) => { if (b && path != null) { Logger.Trace("FindExecTask Success: {0}", path); - - new FuncTask(CancellationToken, () => path) - .Then(afterPathDetermined) - .Start(); + InitializeEnvironment(gitExecutablePath); } else { @@ -119,15 +76,8 @@ public void Run(bool firstRun) var installDetails = new GitInstallDetails(applicationDataPath, true); var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails); - gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken, (b, path) => { - Logger.Trace("GitInstaller Success: {0}", path); - new FuncTask(CancellationToken, () => path) - .Then(afterPathDetermined) - .Start(); - }), new ActionTask(CancellationToken, () => { - Logger.Warning("GitInstaller Failure"); - findExecTask.Start(); - })); + // if successful, continue with environment initialization, otherwise try to find an existing git installation + gitInstaller.SetupGitIfNeeded(initEnvironmentTask, findExecTask); } } @@ -216,6 +166,45 @@ protected void SetupMetrics(string unityVersion, bool firstRun) protected abstract void InitializeUI(); protected abstract void SetProjectToTextSerialization(); + /// + /// Initialize environment after finding where git is. This needs to run on the main thread + /// + /// + private void InitializeEnvironment(NPath gitExecutablePath) + { + var afterGitSetup = new ActionTask(CancellationToken, RestartRepository) + .ThenInUI(InitializeUI); + + Environment.GitExecutablePath = gitExecutablePath; + Environment.User.Initialize(GitClient); + + if (Environment.IsWindows) + { + GitClient + .GetConfig("credential.helper", GitConfigSource.Global) + .Then((b, credentialHelper) => { + if (!string.IsNullOrEmpty(credentialHelper)) + { + Logger.Trace("Windows CredentialHelper: {0}", credentialHelper); + afterGitSetup.Start(); + } + else + { + Logger.Warning("No Windows CredentialHeloper found: Setting to wincred"); + + GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global) + .Then(afterGitSetup) + .Start(); + } + }) + .Start(); + } + else + { + afterGitSetup.Start(); + } + } + private bool disposed = false; protected virtual void Dispose(bool disposing) { diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 2d5f6c92d..20d4904be 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -99,78 +99,67 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) return; } - new FuncTask(cancellationToken, IsGitExtracted) - .Finally((success, ex, isPortableGitExtracted) => { - Logger.Trace("IsPortableGitExtracted: {0}", isPortableGitExtracted); - - if (isPortableGitExtracted) - { - Logger.Trace("SetupGitIfNeeded: Skipped"); - - new FuncTask(cancellationToken, () => installDetails.GitExecPath) - .Then(onSuccess) - .Start(); - } - else - { - ITask downloadFilesTask = null; - if (gitArchiveFilePath == null || gitLfsArchivePath == null) - { - downloadFilesTask = CreateDownloadTask(); - } - - var tempZipExtractPath = NPath.CreateTempDirectory("git_zip_extract_zip_paths"); - var gitExtractPath = tempZipExtractPath.Combine("git").CreateDirectory(); - var gitLfsExtractPath = tempZipExtractPath.Combine("git-lfs").CreateDirectory(); - - var resultTask = new UnzipTask(cancellationToken, gitArchiveFilePath, gitExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitExtractedMD5) - .Then(new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5)) - .Then(() => { - var targetGitLfsExecPath = installDetails.GetGitLfsExecPath(gitExtractPath); - var extractGitLfsExePath = gitLfsExtractPath.Combine(installDetails.GitLfsExec); - - Logger.Trace("Moving Git LFS Exe:\"{0}\" to target in tempDirectory:\"{1}\" ", extractGitLfsExePath, - targetGitLfsExecPath); - - extractGitLfsExePath.Move(targetGitLfsExecPath); - - Logger.Trace("Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", gitExtractPath, - installDetails.GitInstallPath); - - installDetails.GitInstallPath.EnsureParentDirectoryExists(); - gitExtractPath.Move(installDetails.GitInstallPath); - - Logger.Trace("Deleting targetGitLfsExecPath:\"{0}\"", targetGitLfsExecPath); - targetGitLfsExecPath.DeleteIfExists(); - - Logger.Trace("Deleting tempZipPath:\"{0}\"", tempZipExtractPath); - tempZipExtractPath.DeleteIfExists(); - }) - .Finally((b, exception) => { - if (b) - { - Logger.Trace("SetupGitIfNeeded: Success"); - - new FuncTask(cancellationToken, () => installDetails.GitExecPath) - .Then(onSuccess) - .Start(); - } - else - { - Logger.Warning("SetupGitIfNeeded: Failed"); - - onFailure.Start(); - } - }); - - if (downloadFilesTask != null) - { - resultTask = downloadFilesTask.Then(resultTask); - } - - resultTask.Start(); - } - }).Start(); + new ActionTask(cancellationToken, () => { + if (IsGitExtracted()) + { + Logger.Trace("SetupGitIfNeeded: Skipped"); + onSuccess.PreviousResult = installDetails.GitExecPath; + onSuccess.Start(); + } + else + { + ExtractPortableGit(onSuccess, onFailure); + } + }).Start(); + } + + private void ExtractPortableGit(ActionTask onSuccess, ITask onFailure) + { + ITask downloadFilesTask = null; + if (gitArchiveFilePath == null || gitLfsArchivePath == null) + { + downloadFilesTask = CreateDownloadTask(); + } + + var tempZipExtractPath = NPath.CreateTempDirectory("git_zip_extract_zip_paths"); + var gitExtractPath = tempZipExtractPath.Combine("git").CreateDirectory(); + var gitLfsExtractPath = tempZipExtractPath.Combine("git-lfs").CreateDirectory(); + + var resultTask = new UnzipTask(cancellationToken, gitArchiveFilePath, gitExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitExtractedMD5) + .Then(new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5)) + .Then(s => + { + var targetGitLfsExecPath = installDetails.GetGitLfsExecPath(gitExtractPath); + var extractGitLfsExePath = gitLfsExtractPath.Combine(installDetails.GitLfsExec); + + Logger.Trace("Moving Git LFS Exe:\"{0}\" to target in tempDirectory:\"{1}\" ", extractGitLfsExePath, + targetGitLfsExecPath); + + extractGitLfsExePath.Move(targetGitLfsExecPath); + + Logger.Trace("Moving tempDirectory:\"{0}\" to extractTarget:\"{1}\"", gitExtractPath, + installDetails.GitInstallPath); + + installDetails.GitInstallPath.EnsureParentDirectoryExists(); + gitExtractPath.Move(installDetails.GitInstallPath); + + Logger.Trace("Deleting targetGitLfsExecPath:\"{0}\"", targetGitLfsExecPath); + targetGitLfsExecPath.DeleteIfExists(); + + Logger.Trace("Deleting tempZipPath:\"{0}\"", tempZipExtractPath); + tempZipExtractPath.DeleteIfExists(); + return installDetails.GitExecPath; + }); + + resultTask.Then(onFailure, TaskRunOptions.OnFailure); + resultTask.Then(onSuccess, TaskRunOptions.OnSuccess); + + if (downloadFilesTask != null) + { + resultTask = downloadFilesTask.Then(resultTask); + } + + resultTask.Start(); } private ITask CreateDownloadTask() diff --git a/src/GitHub.Api/Tasks/ActionTask.cs b/src/GitHub.Api/Tasks/ActionTask.cs index 4676e7ab9..be0dd6790 100644 --- a/src/GitHub.Api/Tasks/ActionTask.cs +++ b/src/GitHub.Api/Tasks/ActionTask.cs @@ -72,22 +72,42 @@ class ActionTask : TaskBase protected Action Callback { get; } protected Action CallbackWithException { get; } - public ActionTask(CancellationToken token, Action action) + /// + /// + /// + /// + /// + /// Method to call that returns the value that this task is going to work with. You can also use the PreviousResult property to set this value + public ActionTask(CancellationToken token, Action action, Func getPreviousResult = null) : base(token) { Guard.ArgumentNotNull(action, "action"); this.Callback = action; - Task = new Task(() => Run(DependsOn.Successful, DependsOn.Successful ? ((ITask)DependsOn).Result : default(T)), + Task = new Task(() => Run(DependsOn?.Successful ?? true, + // if this task depends on another task and the dependent task was successful, use the value of that other task as input to this task + // otherwise if there's a method to retrieve the value, call that + // otherwise use the PreviousResult property + (DependsOn?.Successful ?? false) ? ((ITask)DependsOn).Result : getPreviousResult != null ? getPreviousResult() : PreviousResult), Token, TaskCreationOptions.None); Name = $"ActionTask<{typeof(T)}>"; } - public ActionTask(CancellationToken token, Action action) + /// + /// + /// + /// + /// + /// Method to call that returns the value that this task is going to work with. You can also use the PreviousResult property to set this value + public ActionTask(CancellationToken token, Action action, Func getPreviousResult = null) : base(token) { Guard.ArgumentNotNull(action, "action"); this.CallbackWithException = action; - Task = new Task(() => Run(DependsOn.Successful, DependsOn.Successful ? ((ITask)DependsOn).Result : default(T)), + Task = new Task(() => Run(DependsOn?.Successful ?? true, + // if this task depends on another task and the dependent task was successful, use the value of that other task as input to this task + // otherwise if there's a method to retrieve the value, call that + // otherwise use the PreviousResult property + (DependsOn?.Successful ?? false) ? ((ITask)DependsOn).Result : getPreviousResult != null ? getPreviousResult() : PreviousResult), Token, TaskCreationOptions.None); Name = $"ActionTask"; } @@ -124,6 +144,8 @@ protected virtual void Run(bool success, T previousResult) RaiseOnEnd(); } } + + public T PreviousResult { get; set; } = default(T); } class FuncTask : TaskBase diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index 5472bdeef..06c0a5600 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -5,14 +5,20 @@ namespace GitHub.Unity { + public enum TaskRunOptions + { + OnSuccess, + OnFailure, + Always + } + public interface ITask : IAsyncResult { - T Then(T continuation, bool always = false) where T : ITask; + T Then(T continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) where T : ITask; ITask Catch(Action handler); ITask Catch(Func handler); ITask Finally(Action handler); ITask Finally(Action actionToContinueWith, TaskAffinity affinity = TaskAffinity.Concurrent); - ITask Defer(Func continueWith, TaskAffinity affinity = TaskAffinity.Concurrent, bool always = false); ITask Start(); ITask Start(TaskScheduler scheduler); ITask Progress(Action progressHandler); @@ -44,7 +50,6 @@ public interface ITask : ITask new Task Task { get; } new event Action> OnStart; new event Action, TResult> OnEnd; - ITask Defer(Func> continueWith, TaskAffinity affinity = TaskAffinity.Concurrent, bool always = false); } interface ITask : ITask @@ -52,8 +57,6 @@ interface ITask : ITask event Action OnData; } - interface IStubTask { } - public abstract class TaskBase : ITask { protected const TaskContinuationOptions runAlwaysOptions = TaskContinuationOptions.None; @@ -65,10 +68,10 @@ public abstract class TaskBase : ITask protected bool previousSuccess = true; protected Exception previousException; - protected object previousResult; - protected TaskBase continuation; - protected bool continuationAlways; + protected TaskBase continuationOnSuccess; + protected TaskBase continuationOnFailure; + protected TaskBase continuationAlways; protected event Func faultHandler; private event Action finallyHandler; @@ -119,18 +122,24 @@ protected TaskBase() this.progress = new Progress { Task = this }; } - public virtual T Then(T cont, bool always = false) + public virtual T Then(T nextTask, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) where T : ITask { - Guard.ArgumentNotNull(cont, nameof(cont)); - var taskBase = ((TaskBase)(object)cont); + Guard.ArgumentNotNull(nextTask, nameof(nextTask)); + var taskBase = ((TaskBase)(object)nextTask); + // find the first task of the continuation chain being appended to this task var firstTaskBase = taskBase.GetTopMostTask() ?? taskBase; + // set this task as a dependency of the first task of the continuation chain firstTaskBase.SetDependsOn(this); - this.continuation = firstTaskBase; - this.continuationAlways = always; - return cont; + if (runOptions == TaskRunOptions.OnSuccess) + this.continuationOnSuccess = firstTaskBase; + else if (runOptions == TaskRunOptions.OnFailure) + this.continuationOnFailure = firstTaskBase; + else + this.continuationAlways = firstTaskBase; + return nextTask; } /// @@ -171,7 +180,7 @@ public ITask Finally(Action handler) public ITask Finally(Action actionToContinueWith, TaskAffinity affinity = TaskAffinity.Concurrent) { Guard.ArgumentNotNull(actionToContinueWith, nameof(actionToContinueWith)); - var ret = Then(new ActionTask(Token, actionToContinueWith) { Affinity = affinity, Name = "Finally" }, true); + var ret = Then(new ActionTask(Token, actionToContinueWith) { Affinity = affinity, Name = "Finally" }, TaskRunOptions.Always); DependsOn?.SetFaultHandler(ret); ret.ContinuationIsFinally = true; return ret; @@ -181,19 +190,10 @@ internal virtual ITask Finally(T taskToContinueWith) where T : TaskBase { Guard.ArgumentNotNull(taskToContinueWith, nameof(taskToContinueWith)); - continuation = (TaskBase)(object)taskToContinueWith; - continuationAlways = true; - continuation.SetDependsOn(this); - DependsOn?.SetFaultHandler((TaskBase)(object)continuation); - return continuation; - } - - public ITask Defer(Func continueWith, TaskAffinity affinity = TaskAffinity.Concurrent, bool always = false) - { - Guard.ArgumentNotNull(continueWith, "continueWith"); - var ret = Then(new StubTask(Token, (s, d) => {}) { Affinity = affinity }); - SetDeferred(new DeferredContinuation { Always = always, GetContinueWith = d => new ActionTask(continueWith((T)d)) { Affinity = affinity, Name = "Deferred" } }); - return ret; + continuationAlways = (TaskBase)(object)taskToContinueWith; + continuationAlways.SetDependsOn(this); + DependsOn?.SetFaultHandler(continuationAlways); + return continuationAlways; } internal void SetFaultHandler(TaskBase handler) @@ -261,11 +261,28 @@ public virtual ITask Start(TaskScheduler scheduler) protected virtual void RunContinuation() { - if (continuation != null) + if (continuationOnSuccess != null) { //Logger.Trace($"Setting ContinueWith {Affinity} {continuation}"); - Task.ContinueWith(_ => ((TaskBase)(object)continuation).Run(), Token, continuationAlways ? runAlwaysOptions : runOnSuccessOptions, - TaskManager.GetScheduler(continuation.Affinity)); + Task.ContinueWith(_ => ((TaskBase)(object)continuationOnSuccess).Run(), Token, + runOnSuccessOptions, + TaskManager.GetScheduler(continuationOnSuccess.Affinity)); + } + + if (continuationOnFailure != null) + { + //Logger.Trace($"Setting ContinueWith {Affinity} {continuation}"); + Task.ContinueWith(_ => ((TaskBase)(object)continuationOnFailure).Run(), Token, + runOnFaultOptions, + TaskManager.GetScheduler(continuationOnFailure.Affinity)); + } + + if (continuationAlways != null) + { + //Logger.Trace($"Setting ContinueWith {Affinity} {continuation}"); + Task.ContinueWith(_ => ((TaskBase)(object)continuationAlways).Run(), Token, + runAlwaysOptions, + TaskManager.GetScheduler(continuationAlways.Affinity)); } } @@ -323,7 +340,7 @@ protected virtual void RaiseOnStart() protected virtual void RaiseOnEnd() { OnEnd?.Invoke(this); - if (continuation == null) + if (continuationOnSuccess == null && continuationOnFailure == null) finallyHandler?.Invoke(); //Logger.Trace($"Finished {ToString()}"); } @@ -361,28 +378,6 @@ protected void UpdateProgress(long value, long total) progressHandler?.Invoke(progress); } - protected class DeferredContinuation - { - public bool Always; - public Func GetContinueWith; - } - - private DeferredContinuation deferred; - internal object GetDeferred() - { - return deferred; - } - - internal void SetDeferred(object def) - { - deferred = (DeferredContinuation)def; - } - - internal void ClearDeferred() - { - deferred = null; - } - public override string ToString() { return $"{Task?.Id ?? -1} {Name} {GetType()}"; @@ -401,18 +396,7 @@ public override string ToString() protected ILogging Logger { get { return logger = logger ?? LogHelper.GetLogger(GetType()); } } public TaskBase DependsOn { get; private set; } public CancellationToken Token { get; } - internal TaskBase Continuation => continuation; - internal bool ContinuationAlways => continuationAlways; internal bool ContinuationIsFinally { get; set; } - - class StubTask : ActionTask, IStubTask - { - public StubTask(CancellationToken token, Action func) - : base(token, func) - { - Name = "Stub"; - } - } } abstract class TaskBase : TaskBase, ITask @@ -430,7 +414,6 @@ public TaskBase(CancellationToken token) { var ret = RunWithReturn(DependsOn?.Successful ?? previousSuccess); tcs.SetResult(ret); - AdjustNextTask(ret); return ret; }, Token, TaskCreationOptions.None); } @@ -466,40 +449,9 @@ public TaskBase(Task task) }, task, Token, TaskCreationOptions.None); } - - protected void AdjustNextTask(TResult ret) + public override T Then(T continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { - var def = GetDeferred(); - if (def != null) - { - var next = (def as DeferredContinuation)?.GetContinueWith(ret); - var cont = continuation.Continuation; - var nextDefer = continuation.GetDeferred(); - if (continuation is IStubTask) - { - ((TaskBase)next).SetDeferred(nextDefer); - ((TaskBase)continuation).ClearDeferred(); - } - - if (cont != null) - { - if (cont.ContinuationIsFinally) - { - ((TaskBase)next).Finally(cont); - } - else - { - next.Then(cont, cont.ContinuationAlways); - } - } - continuation.Then(next, continuationAlways); - ClearDeferred(); - } - } - - public override T Then(T continuation, bool always = false) - { - return base.Then(continuation, always); + return base.Then(continuation, runOptions); } /// @@ -528,23 +480,6 @@ public override T Then(T continuation, bool always = false) return this; } - public ITask Defer(Func> continueWith, TaskAffinity affinity = TaskAffinity.Concurrent, bool always = false) - { - Guard.ArgumentNotNull(continueWith, "continueWith"); - var ret = Then(new StubTask(Token, (s, d) => default(T)) { Affinity = affinity }, always); - SetDeferred(new DeferredContinuation { Always = always, GetContinueWith = d => new FuncTask(continueWith((TResult)d)) { Affinity = affinity, Name = "Deferred" } }); - return ret; - } - - class StubTask : FuncTask, IStubTask - { - public StubTask(CancellationToken token, Func func) - : base(token, func) - { - Name = "Stub"; - } - } - /// /// This finally will always run on the same thread as the last task that runs /// @@ -559,7 +494,7 @@ public ITask Finally(Action handler) public ITask Finally(Func continuation, TaskAffinity affinity = TaskAffinity.Concurrent) { Guard.ArgumentNotNull(continuation, "continuation"); - var ret = Then(new FuncTask(Token, continuation) { Affinity = affinity, Name = "Finally" }, true); + var ret = Then(new FuncTask(Token, continuation) { Affinity = affinity, Name = "Finally" }, TaskRunOptions.Always); ret.ContinuationIsFinally = true; DependsOn?.SetFaultHandler(ret); return ret; @@ -568,7 +503,7 @@ public ITask Finally(Func continuati public ITask Finally(Action continuation, TaskAffinity affinity = TaskAffinity.Concurrent) { Guard.ArgumentNotNull(continuation, "continuation"); - var ret = Then(new ActionTask(Token, continuation) { Affinity = affinity, Name = "Finally" }, true); + var ret = Then(new ActionTask(Token, continuation) { Affinity = affinity, Name = "Finally" }, TaskRunOptions.Always); ret.ContinuationIsFinally = true; DependsOn?.SetFaultHandler(ret); return ret; @@ -612,7 +547,7 @@ protected override void RaiseOnStart() protected virtual void RaiseOnEnd(TResult result) { OnEnd?.Invoke(this, result); - if (continuation == null) + if (continuationOnSuccess == null && continuationOnFailure == null) finallyHandler?.Invoke(result); //Logger.Trace($"Finished {ToString()} {result}"); } @@ -634,7 +569,6 @@ public TaskBase(CancellationToken token) { var ret = RunWithData(DependsOn?.Successful ?? previousSuccess, (DependsOn?.Successful ?? false) ? ((ITask)DependsOn).Result : default(T)); tcs.SetResult(ret); - AdjustNextTask(ret); return ret; }, Token, TaskCreationOptions.None); diff --git a/src/GitHub.Api/Tasks/TaskExtensions.cs b/src/GitHub.Api/Tasks/TaskExtensions.cs index 71e0f9201..f2fcdf006 100644 --- a/src/GitHub.Api/Tasks/TaskExtensions.cs +++ b/src/GitHub.Api/Tasks/TaskExtensions.cs @@ -121,82 +121,89 @@ public static Action Debounce(this Action func, int milliseconds = 300) }; } - public static ITask Then(this ITask task, Action continuation, bool always = false) + public static ITask Then(this ITask task, Action continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { Guard.ArgumentNotNull(continuation, "continuation"); - return task.Then(new ActionTask(task.Token, _ => continuation()) { Name = "Then" }, always); + return task.Then(new ActionTask(task.Token, _ => continuation()) { Name = "Then" }, runOptions); } - public static ITask Then(this ITask task, Action continuation, TaskAffinity affinity, bool always = false) + public static ITask Then(this ITask task, Action continuation, TaskAffinity affinity, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { Guard.ArgumentNotNull(continuation, "continuation"); - return task.Then(new ActionTask(task.Token, _ => continuation()) { Affinity = affinity, Name = "Then" }, always); + return task.Then(new ActionTask(task.Token, _ => continuation()) { Affinity = affinity, Name = "Then" }, runOptions); } - public static ITask Then(this ITask task, Action continuation, bool always = false) + public static ITask Then(this ITask task, Action continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { Guard.ArgumentNotNull(continuation, "continuation"); - return task.Then(new ActionTask(task.Token, continuation) { Name = "Then" }, always); + return task.Then(new ActionTask(task.Token, continuation) { Name = "Then" }, runOptions); } - public static ITask Then(this ITask task, Action continuation, TaskAffinity affinity, bool always = false) + public static ITask Then(this ITask task, Action continuation, TaskAffinity affinity, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { Guard.ArgumentNotNull(continuation, "continuation"); - return task.Then(new ActionTask(task.Token, continuation) { Affinity = affinity, Name = "Then" }, always); + return task.Then(new ActionTask(task.Token, continuation) { Affinity = affinity, Name = "Then" }, runOptions); } - public static ITask Then(this ITask task, Action continuation, TaskAffinity affinity = TaskAffinity.Concurrent, bool always = false) + public static ITask Then(this ITask task, ActionTask nextTask, T valueForNextTask, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) + { + Guard.ArgumentNotNull(nextTask, nameof(nextTask)); + nextTask.PreviousResult = valueForNextTask; + return task.Then(nextTask, runOptions); + } + + public static ITask Then(this ITask task, Action continuation, TaskAffinity affinity = TaskAffinity.Concurrent, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { Guard.ArgumentNotNull(continuation, "continuation"); - return task.Then(new ActionTask(task.Token, continuation) { Affinity = affinity, Name = $"Then<{typeof(T)}>" }, always); + return task.Then(new ActionTask(task.Token, continuation) { Affinity = affinity, Name = $"Then<{typeof(T)}>" }, runOptions); } - public static ITask Then(this ITask task, Func continuation, TaskAffinity affinity = TaskAffinity.Concurrent, bool always = false) + public static ITask Then(this ITask task, Func continuation, TaskAffinity affinity = TaskAffinity.Concurrent, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { Guard.ArgumentNotNull(continuation, "continuation"); - return task.Then(new FuncTask(task.Token, continuation) { Affinity = affinity, Name = $"Then<{typeof(T)}>" }, always); + return task.Then(new FuncTask(task.Token, continuation) { Affinity = affinity, Name = $"Then<{typeof(T)}>" }, runOptions); } - public static ITask Then(this ITask task, Func continuation, TaskAffinity affinity = TaskAffinity.Concurrent, bool always = false) + public static ITask Then(this ITask task, Func continuation, TaskAffinity affinity = TaskAffinity.Concurrent, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { Guard.ArgumentNotNull(continuation, "continuation"); - return task.Then(new FuncTask(task.Token, continuation) { Affinity = affinity, Name = $"Then<{typeof(T)}, {typeof(TRet)}>" }, always); + return task.Then(new FuncTask(task.Token, continuation) { Affinity = affinity, Name = $"Then<{typeof(T)}, {typeof(TRet)}>" }, runOptions); } - public static ITask Then(this ITask task, Task continuation, TaskAffinity affinity = TaskAffinity.Concurrent, bool always = false) + public static ITask Then(this ITask task, Task continuation, TaskAffinity affinity = TaskAffinity.Concurrent, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { var cont = new FuncTask(continuation) { Affinity = affinity, Name = $"ThenAsync<{typeof(T)}>" }; - return task.Then(cont, always); + return task.Then(cont, runOptions); } - public static ITask Then(this ITask task, Func> continuation, TaskAffinity affinity = TaskAffinity.Concurrent, bool always = false) + public static ITask Then(this ITask task, Func> continuation, TaskAffinity affinity = TaskAffinity.Concurrent, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { - return task.Then(continuation(), affinity, always); + return task.Then(continuation(), affinity, runOptions); } - public static ITask ThenInUI(this ITask task, Action continuation, bool always = false) + public static ITask ThenInUI(this ITask task, Action continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { - return task.Then(continuation, TaskAffinity.UI, always); + return task.Then(continuation, TaskAffinity.UI, runOptions); } - public static ITask ThenInUI(this ITask task, Action continuation, bool always = false) + public static ITask ThenInUI(this ITask task, Action continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { - return task.Then(continuation, TaskAffinity.UI, always); + return task.Then(continuation, TaskAffinity.UI, runOptions); } - public static ITask ThenInUI(this ITask task, Action continuation, bool always = false) + public static ITask ThenInUI(this ITask task, Action continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { - return task.Then(continuation, TaskAffinity.UI, always); + return task.Then(continuation, TaskAffinity.UI, runOptions); } - public static ITask ThenInUI(this ITask task, Func continuation, bool always = false) + public static ITask ThenInUI(this ITask task, Func continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { - return task.Then(continuation, TaskAffinity.UI, always); + return task.Then(continuation, TaskAffinity.UI, runOptions); } - public static ITask ThenInUI(this ITask task, Func continuation, bool always = false) + public static ITask ThenInUI(this ITask task, Func continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { - return task.Then(continuation, TaskAffinity.UI, always); + return task.Then(continuation, TaskAffinity.UI, runOptions); } public static ITask FinallyInUI(this T task, Action continuation) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs index b2da0f974..958b79b97 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs @@ -677,7 +677,7 @@ private void Pull() // whether pull triggered a merge or a rebase, and abort the operation accordingly // (either git rebase --abort or git merge --abort) } - }, true) + }, TaskRunOptions.Always) .FinallyInUI((success, e) => { if (success) { From 70b9da2a08bc10fc947b4d176315f66e5cea1122 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Wed, 31 Jan 2018 22:37:14 +0100 Subject: [PATCH 0133/1008] The inthread finally handler only gets called at the very end --- src/GitHub.Api/Tasks/TaskBase.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index 06c0a5600..d01556d08 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -19,6 +19,7 @@ public interface ITask : IAsyncResult ITask Catch(Func handler); ITask Finally(Action handler); ITask Finally(Action actionToContinueWith, TaskAffinity affinity = TaskAffinity.Concurrent); + ITask Finally(T taskToContinueWith) where T : ITask; ITask Start(); ITask Start(TaskScheduler scheduler); ITask Progress(Action progressHandler); @@ -180,14 +181,11 @@ public ITask Finally(Action handler) public ITask Finally(Action actionToContinueWith, TaskAffinity affinity = TaskAffinity.Concurrent) { Guard.ArgumentNotNull(actionToContinueWith, nameof(actionToContinueWith)); - var ret = Then(new ActionTask(Token, actionToContinueWith) { Affinity = affinity, Name = "Finally" }, TaskRunOptions.Always); - DependsOn?.SetFaultHandler(ret); - ret.ContinuationIsFinally = true; - return ret; + return Finally(new ActionTask(Token, actionToContinueWith) { Affinity = affinity, Name = "Finally" }); } - internal virtual ITask Finally(T taskToContinueWith) - where T : TaskBase + public ITask Finally(T taskToContinueWith) + where T : ITask { Guard.ArgumentNotNull(taskToContinueWith, nameof(taskToContinueWith)); continuationAlways = (TaskBase)(object)taskToContinueWith; @@ -340,7 +338,7 @@ protected virtual void RaiseOnStart() protected virtual void RaiseOnEnd() { OnEnd?.Invoke(this); - if (continuationOnSuccess == null && continuationOnFailure == null) + if (continuationOnSuccess == null && continuationOnFailure == null && continuationAlways == null) finallyHandler?.Invoke(); //Logger.Trace($"Finished {ToString()}"); } @@ -396,7 +394,6 @@ public override string ToString() protected ILogging Logger { get { return logger = logger ?? LogHelper.GetLogger(GetType()); } } public TaskBase DependsOn { get; private set; } public CancellationToken Token { get; } - internal bool ContinuationIsFinally { get; set; } } abstract class TaskBase : TaskBase, ITask @@ -495,7 +492,6 @@ public ITask Finally(Func continuati { Guard.ArgumentNotNull(continuation, "continuation"); var ret = Then(new FuncTask(Token, continuation) { Affinity = affinity, Name = "Finally" }, TaskRunOptions.Always); - ret.ContinuationIsFinally = true; DependsOn?.SetFaultHandler(ret); return ret; } @@ -504,7 +500,6 @@ public ITask Finally(Action continuation, TaskAffinity { Guard.ArgumentNotNull(continuation, "continuation"); var ret = Then(new ActionTask(Token, continuation) { Affinity = affinity, Name = "Finally" }, TaskRunOptions.Always); - ret.ContinuationIsFinally = true; DependsOn?.SetFaultHandler(ret); return ret; } @@ -547,7 +542,7 @@ protected override void RaiseOnStart() protected virtual void RaiseOnEnd(TResult result) { OnEnd?.Invoke(this, result); - if (continuationOnSuccess == null && continuationOnFailure == null) + if (continuationOnSuccess == null && continuationOnFailure == null && continuationAlways == null) finallyHandler?.Invoke(result); //Logger.Trace($"Finished {ToString()} {result}"); } From 577e24383f275c6c838b4d88490cc2fdc92017b5 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 1 Feb 2018 16:46:03 +0100 Subject: [PATCH 0134/1008] Make sure fault handlers are always called when merging two chains --- src/GitHub.Api/Tasks/TaskBase.cs | 60 ++++++++++++------- .../Editor/GitHub.Unity/UI/HistoryView.cs | 2 +- src/tests/TaskSystemIntegrationTests/Tests.cs | 19 ++++++ 3 files changed, 59 insertions(+), 22 deletions(-) diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index d01556d08..e4dd29e85 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -9,7 +9,7 @@ public enum TaskRunOptions { OnSuccess, OnFailure, - Always + OnAlways } public interface ITask : IAsyncResult @@ -72,9 +72,9 @@ public abstract class TaskBase : ITask protected TaskBase continuationOnSuccess; protected TaskBase continuationOnFailure; - protected TaskBase continuationAlways; + protected TaskBase continuationOnAlways; - protected event Func faultHandler; + protected event Func catchHandler; private event Action finallyHandler; protected event Action progressHandler; @@ -135,11 +135,29 @@ public virtual T Then(T nextTask, TaskRunOptions runOptions = TaskRunOptions. firstTaskBase.SetDependsOn(this); if (runOptions == TaskRunOptions.OnSuccess) + { this.continuationOnSuccess = firstTaskBase; + // if there are fault handlers in the chain we're appending, propagate them + // up this chain as well + if (firstTaskBase.continuationOnFailure != null) + SetFaultHandler(firstTaskBase.continuationOnFailure); + else if (firstTaskBase.continuationOnAlways != null) + SetFaultHandler(firstTaskBase.continuationOnAlways); + if (firstTaskBase.catchHandler != null) + Catch(firstTaskBase.catchHandler); + if (firstTaskBase.finallyHandler != null) + Finally(firstTaskBase.finallyHandler); + } else if (runOptions == TaskRunOptions.OnFailure) + { this.continuationOnFailure = firstTaskBase; + DependsOn?.SetFaultHandler(firstTaskBase); + } else - this.continuationAlways = firstTaskBase; + { + this.continuationOnAlways = firstTaskBase; + DependsOn?.SetFaultHandler(firstTaskBase); + } return nextTask; } @@ -150,7 +168,7 @@ public virtual T Then(T nextTask, TaskRunOptions runOptions = TaskRunOptions. public ITask Catch(Action handler) { Guard.ArgumentNotNull(handler, "handler"); - faultHandler += e => { handler(e); return false; }; + catchHandler += e => { handler(e); return false; }; DependsOn?.Catch(handler); return this; } @@ -162,7 +180,7 @@ public ITask Catch(Action handler) public ITask Catch(Func handler) { Guard.ArgumentNotNull(handler, "handler"); - faultHandler += handler; + catchHandler += handler; DependsOn?.Catch(handler); return this; } @@ -188,10 +206,10 @@ public ITask Finally(T taskToContinueWith) where T : ITask { Guard.ArgumentNotNull(taskToContinueWith, nameof(taskToContinueWith)); - continuationAlways = (TaskBase)(object)taskToContinueWith; - continuationAlways.SetDependsOn(this); - DependsOn?.SetFaultHandler(continuationAlways); - return continuationAlways; + continuationOnAlways = (TaskBase)(object)taskToContinueWith; + continuationOnAlways.SetDependsOn(this); + DependsOn?.SetFaultHandler(continuationOnAlways); + return continuationOnAlways; } internal void SetFaultHandler(TaskBase handler) @@ -275,12 +293,12 @@ protected virtual void RunContinuation() TaskManager.GetScheduler(continuationOnFailure.Affinity)); } - if (continuationAlways != null) + if (continuationOnAlways != null) { //Logger.Trace($"Setting ContinueWith {Affinity} {continuation}"); - Task.ContinueWith(_ => ((TaskBase)(object)continuationAlways).Run(), Token, + Task.ContinueWith(_ => ((TaskBase)(object)continuationOnAlways).Run(), Token, runAlwaysOptions, - TaskManager.GetScheduler(continuationAlways.Affinity)); + TaskManager.GetScheduler(continuationOnAlways.Affinity)); } } @@ -338,17 +356,17 @@ protected virtual void RaiseOnStart() protected virtual void RaiseOnEnd() { OnEnd?.Invoke(this); - if (continuationOnSuccess == null && continuationOnFailure == null && continuationAlways == null) + if (continuationOnSuccess == null && continuationOnFailure == null && continuationOnAlways == null) finallyHandler?.Invoke(); //Logger.Trace($"Finished {ToString()}"); } protected virtual bool RaiseFaultHandlers(Exception ex) { - if (faultHandler == null) + if (catchHandler == null) return false; bool handled = false; - foreach (var handler in faultHandler.GetInvocationList()) + foreach (var handler in catchHandler.GetInvocationList()) { handled |= (bool)handler.DynamicInvoke(new object[] { ex }); if (handled) @@ -459,7 +477,7 @@ public override T Then(T continuation, TaskRunOptions runOptions = TaskRunOpt public new ITask Catch(Action handler) { Guard.ArgumentNotNull(handler, "handler"); - faultHandler += e => { handler(e); return false; }; + catchHandler += e => { handler(e); return false; }; DependsOn?.Catch(handler); return this; } @@ -472,7 +490,7 @@ public override T Then(T continuation, TaskRunOptions runOptions = TaskRunOpt public new ITask Catch(Func handler) { Guard.ArgumentNotNull(handler, "handler"); - faultHandler += handler; + catchHandler += handler; DependsOn?.Catch(handler); return this; } @@ -491,7 +509,7 @@ public ITask Finally(Action handler) public ITask Finally(Func continuation, TaskAffinity affinity = TaskAffinity.Concurrent) { Guard.ArgumentNotNull(continuation, "continuation"); - var ret = Then(new FuncTask(Token, continuation) { Affinity = affinity, Name = "Finally" }, TaskRunOptions.Always); + var ret = Then(new FuncTask(Token, continuation) { Affinity = affinity, Name = "Finally" }, TaskRunOptions.OnAlways); DependsOn?.SetFaultHandler(ret); return ret; } @@ -499,7 +517,7 @@ public ITask Finally(Func continuati public ITask Finally(Action continuation, TaskAffinity affinity = TaskAffinity.Concurrent) { Guard.ArgumentNotNull(continuation, "continuation"); - var ret = Then(new ActionTask(Token, continuation) { Affinity = affinity, Name = "Finally" }, TaskRunOptions.Always); + var ret = Then(new ActionTask(Token, continuation) { Affinity = affinity, Name = "Finally" }, TaskRunOptions.OnAlways); DependsOn?.SetFaultHandler(ret); return ret; } @@ -542,7 +560,7 @@ protected override void RaiseOnStart() protected virtual void RaiseOnEnd(TResult result) { OnEnd?.Invoke(this, result); - if (continuationOnSuccess == null && continuationOnFailure == null && continuationAlways == null) + if (continuationOnSuccess == null && continuationOnFailure == null && continuationOnAlways == null) finallyHandler?.Invoke(result); //Logger.Trace($"Finished {ToString()} {result}"); } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs index 958b79b97..ea3e307f1 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/HistoryView.cs @@ -677,7 +677,7 @@ private void Pull() // whether pull triggered a merge or a rebase, and abort the operation accordingly // (either git rebase --abort or git merge --abort) } - }, TaskRunOptions.Always) + }, TaskRunOptions.OnAlways) .FinallyInUI((success, e) => { if (success) { diff --git a/src/tests/TaskSystemIntegrationTests/Tests.cs b/src/tests/TaskSystemIntegrationTests/Tests.cs index 44ce4e36d..8e1829698 100644 --- a/src/tests/TaskSystemIntegrationTests/Tests.cs +++ b/src/tests/TaskSystemIntegrationTests/Tests.cs @@ -666,6 +666,25 @@ public async Task StartAwaitSafelyAwaits() .Catch(_ => { }); await task.StartAwait(_ => { }); } + + [Test] + public async Task TaskOnFailureGetsCalledWhenExceptionHappensUpTheChain() + { + var runOrder = new List(); + var exceptions = new List(); + var task = new ActionTask(Token, _ => { throw new InvalidOperationException(); }) + .Then(_ => { runOrder.Add("1"); }) + .Catch(ex => exceptions.Add(ex)) + .Then(() => runOrder.Add("OnFailure"), TaskRunOptions.OnFailure) + .Finally((s, e) => { }); + await task.StartAndSwallowException(); + CollectionAssert.AreEqual( + new string[] { typeof(InvalidOperationException).Name }, + exceptions.Select(x => x.GetType().Name).ToArray()); + CollectionAssert.AreEqual( + new string[] { "OnFailure" }, + runOrder); + } } [TestFixture] From c1558a53c4cbf5d5216319f749640143fd8c19c8 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 1 Feb 2018 16:46:51 +0100 Subject: [PATCH 0135/1008] Adding donwloading the files to the git installer test --- .../Installer/GitInstallerTests.cs | 37 ++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs index 87b9fd752..2597df2fc 100644 --- a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs +++ b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs @@ -1,5 +1,6 @@ using System; using System.Threading; +using System.Threading.Tasks; using FluentAssertions; using GitHub.Unity; using NSubstitute; @@ -10,24 +11,42 @@ namespace IntegrationTests [TestFixture] class GitInstallerTests : BaseTaskManagerTest { - [Test] - public void GitInstallTest() + const int Timeout = 30000; + public override void OnSetup() { - InitializeTaskManager(); + base.OnSetup(); + InitializeEnvironment(TestBasePath, initializeRepository: false); + } - var cacheContainer = Substitute.For(); - Environment = new IntegrationTestEnvironment(cacheContainer, TestBasePath, SolutionDirectory, enableTrace: true); + private TestWebServer.HttpServer server; + public override void TestFixtureSetUp() + { + base.TestFixtureSetUp(); + server = new TestWebServer.HttpServer(SolutionDirectory.Combine("files")); + Task.Factory.StartNew(server.Start); + ApplicationConfiguration.WebTimeout = 5000; + } + public override void TestFixtureTearDown() + { + base.TestFixtureTearDown(); + server.Stop(); + ApplicationConfiguration.WebTimeout = ApplicationConfiguration.DefaultWebTimeout; + } + + [Test] + public void GitInstallTest() + { var gitInstallationPath = TestBasePath.Combine("GitInstall").CreateDirectory(); var installDetails = new GitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows); - var zipArchivesPath = TestBasePath.Combine("ZipArchives").CreateDirectory(); + //var zipArchivesPath = TestBasePath.Combine("ZipArchives").CreateDirectory(); - var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); - var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); + //var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); + //var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); - var gitInstaller = new GitInstaller(Environment, CancellationToken.None, installDetails, gitArchivePath, gitLfsArchivePath); + var gitInstaller = new GitInstaller(Environment, CancellationToken.None, installDetails); var autoResetEvent = new AutoResetEvent(false); From 79af1d083c87ea55af3745a535bb21dde2e9c68b Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 1 Feb 2018 17:52:44 +0100 Subject: [PATCH 0136/1008] Make sure fault handlers are set correctly --- src/GitHub.Api/Tasks/TaskBase.cs | 46 +++++++++++++++++--------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index e4dd29e85..ed01ff7ee 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -127,36 +127,37 @@ public virtual T Then(T nextTask, TaskRunOptions runOptions = TaskRunOptions. where T : ITask { Guard.ArgumentNotNull(nextTask, nameof(nextTask)); - var taskBase = ((TaskBase)(object)nextTask); + var nextTaskBase = ((TaskBase)(object)nextTask); - // find the first task of the continuation chain being appended to this task - var firstTaskBase = taskBase.GetTopMostTask() ?? taskBase; - // set this task as a dependency of the first task of the continuation chain - firstTaskBase.SetDependsOn(this); + // find the task at the top of the chain + nextTaskBase = nextTaskBase.GetTopMostTask() ?? nextTaskBase; + // make the next task dependent on this one so it can get values from us + nextTaskBase.SetDependsOn(this); if (runOptions == TaskRunOptions.OnSuccess) { - this.continuationOnSuccess = firstTaskBase; + this.continuationOnSuccess = nextTaskBase; + // if there are fault handlers in the chain we're appending, propagate them // up this chain as well - if (firstTaskBase.continuationOnFailure != null) - SetFaultHandler(firstTaskBase.continuationOnFailure); - else if (firstTaskBase.continuationOnAlways != null) - SetFaultHandler(firstTaskBase.continuationOnAlways); - if (firstTaskBase.catchHandler != null) - Catch(firstTaskBase.catchHandler); - if (firstTaskBase.finallyHandler != null) - Finally(firstTaskBase.finallyHandler); + if (nextTaskBase.continuationOnFailure != null) + SetFaultHandler(nextTaskBase.continuationOnFailure); + else if (nextTaskBase.continuationOnAlways != null) + SetFaultHandler(nextTaskBase.continuationOnAlways); + if (nextTaskBase.catchHandler != null) + Catch(nextTaskBase.catchHandler); + if (nextTaskBase.finallyHandler != null) + Finally(nextTaskBase.finallyHandler); } else if (runOptions == TaskRunOptions.OnFailure) { - this.continuationOnFailure = firstTaskBase; - DependsOn?.SetFaultHandler(firstTaskBase); + this.continuationOnFailure = nextTaskBase; + DependsOn?.SetFaultHandler(nextTaskBase); } else { - this.continuationOnAlways = firstTaskBase; - DependsOn?.SetFaultHandler(firstTaskBase); + this.continuationOnAlways = nextTaskBase; + DependsOn?.SetFaultHandler(nextTaskBase); } return nextTask; } @@ -214,9 +215,12 @@ public ITask Finally(T taskToContinueWith) internal void SetFaultHandler(TaskBase handler) { - Task.ContinueWith(t => handler.Start(t), Token, - TaskContinuationOptions.OnlyOnFaulted, - TaskManager.GetScheduler(handler.Affinity)); + if (Task.Status == TaskStatus.Created) + this.continuationOnFailure = handler; + else + Task.ContinueWith(t => handler.Start(t), Token, + TaskContinuationOptions.OnlyOnFaulted, + TaskManager.GetScheduler(handler.Affinity)); DependsOn?.SetFaultHandler(handler); } From 690dec233af72d30f4787bd233c1f7362dec9431 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 1 Feb 2018 17:53:04 +0100 Subject: [PATCH 0137/1008] Fix git installer test --- src/GitHub.Api/Installer/GitInstaller.cs | 30 ++++++++++++------- src/GitHub.Api/Tasks/DownloadTask.cs | 4 +++ .../Installer/GitInstallerTests.cs | 12 ++++++-- src/tests/TestWebServer/TestWebServer.csproj | 6 ++++ src/tests/TestWebServer/files/git.zip | 3 ++ src/tests/TestWebServer/files/git.zip.MD5.txt | 1 + 6 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 src/tests/TestWebServer/files/git.zip create mode 100644 src/tests/TestWebServer/files/git.zip.MD5.txt diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 20d4904be..53cdce962 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -11,6 +11,16 @@ class GitInstallDetails public NPath GitExecPath { get; } public string GitLfsExec { get; } public NPath GitLfsExecPath { get; } + public UriString GitZipMd5Url { get; set; } = DefaultGitZipMd5Url; + public UriString GitZipUrl { get; set; } = DefaultGitZipUrl; + public UriString GitLfsZipMd5Url { get; set; } = DefaultGitLfsZipMd5Url; + public UriString GitLfsZipUrl { get; set; } = DefaultGitLfsZipUrl; + + public const string DefaultGitZipMd5Url = "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt"; + 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.txt"; + public const string DefaultGitLfsZipUrl = "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip"; + public const string GitExtractedMD5 = "e6cfc0c294a2312042f27f893dfc9c0a"; public const string GitLfsExtractedMD5 = "36e3ae968b69fbf42dff72311040d24a"; @@ -165,25 +175,25 @@ private void ExtractPortableGit(ActionTask onSuccess, ITask onFailure) private ITask CreateDownloadTask() { var tempZipPath = NPath.CreateTempDirectory("git_zip_paths"); - gitArchiveFilePath = tempZipPath.Combine("git"); - gitLfsArchivePath = tempZipPath.Combine("git-lfs"); + gitArchiveFilePath = tempZipPath.Combine("git.zip"); + gitLfsArchivePath = tempZipPath.Combine("git-lfs.zip"); var downloadGitMd5Task = new DownloadTextTask(TaskManager.Instance.Token, environment.FileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt", - gitArchiveFilePath); + installDetails.GitZipMd5Url, + tempZipPath); var downloadGitTask = new DownloadTask(TaskManager.Instance.Token, environment.FileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git.zip", - gitArchiveFilePath, retryCount: 1); + installDetails.GitZipUrl, + tempZipPath); var downloadGitLfsMd5Task = new DownloadTextTask(TaskManager.Instance.Token, environment.FileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip.MD5.txt", - gitLfsArchivePath); + installDetails.GitLfsZipMd5Url, + tempZipPath); var downloadGitLfsTask = new DownloadTask(TaskManager.Instance.Token, environment.FileSystem, - "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip", - gitLfsArchivePath, retryCount: 1); + installDetails.GitLfsZipUrl, + tempZipPath); return downloadGitMd5Task .Then((b, s) => { diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index e51c38e66..98aee8240 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -141,6 +141,10 @@ protected virtual string RunDownload(bool success) return Destination; } + public override string ToString() + { + return $"{base.ToString()} {Url}"; + } public UriString Url { get; } diff --git a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs index 2597df2fc..900b428e3 100644 --- a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs +++ b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs @@ -24,7 +24,7 @@ public override void TestFixtureSetUp() base.TestFixtureSetUp(); server = new TestWebServer.HttpServer(SolutionDirectory.Combine("files")); Task.Factory.StartNew(server.Start); - ApplicationConfiguration.WebTimeout = 5000; + ApplicationConfiguration.WebTimeout = 10000; } public override void TestFixtureTearDown() @@ -39,9 +39,15 @@ public void GitInstallTest() { var gitInstallationPath = TestBasePath.Combine("GitInstall").CreateDirectory(); - var installDetails = new GitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows); + var installDetails = new GitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows) + { + GitZipMd5Url = $"http://localhost:{server.Port}/{new UriString(GitInstallDetails.DefaultGitZipMd5Url).Filename}", + GitZipUrl = $"http://localhost:{server.Port}/{new UriString(GitInstallDetails.DefaultGitZipUrl).Filename}", + GitLfsZipMd5Url = $"http://localhost:{server.Port}/{new UriString(GitInstallDetails.DefaultGitLfsZipMd5Url).Filename}", + GitLfsZipUrl = $"http://localhost:{server.Port}/{new UriString(GitInstallDetails.DefaultGitLfsZipUrl).Filename}", + }; - //var zipArchivesPath = TestBasePath.Combine("ZipArchives").CreateDirectory(); + TestBasePath.Combine("git").CreateDirectory(); //var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); //var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); diff --git a/src/tests/TestWebServer/TestWebServer.csproj b/src/tests/TestWebServer/TestWebServer.csproj index 6e0ef21c7..65a7e69a5 100644 --- a/src/tests/TestWebServer/TestWebServer.csproj +++ b/src/tests/TestWebServer/TestWebServer.csproj @@ -46,11 +46,17 @@ PreserveNewest + + PreserveNewest + PreserveNewest + + PreserveNewest + diff --git a/src/tests/TestWebServer/files/git.zip b/src/tests/TestWebServer/files/git.zip new file mode 100644 index 000000000..c575bd970 --- /dev/null +++ b/src/tests/TestWebServer/files/git.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:24864bd6ed4d60a516330107932082ae17ae5b98b0819d6cb6eba4a96b7ae0e4 +size 83230267 diff --git a/src/tests/TestWebServer/files/git.zip.MD5.txt b/src/tests/TestWebServer/files/git.zip.MD5.txt new file mode 100644 index 000000000..c03682ca5 --- /dev/null +++ b/src/tests/TestWebServer/files/git.zip.MD5.txt @@ -0,0 +1 @@ +EA5D5A38A6B9E9BC2B10011602C65A0D \ No newline at end of file From 8248c499e94a1b4003803759de8c63871ad6a8e0 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Feb 2018 12:41:15 -0500 Subject: [PATCH 0138/1008] The log only sends one update when switching branches --- src/tests/IntegrationTests/Events/RepositoryManagerTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs index 44191d1b3..065f7b4d7 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -572,7 +572,6 @@ await RepositoryManager.SwitchBranch("branch2") repositoryManagerEvents.CurrentBranchUpdated.WaitOne(Timeout).Should().BeTrue(); repositoryManagerEvents.GitLogUpdated.WaitOne(Timeout).Should().BeTrue(); - repositoryManagerEvents.GitLogUpdated.WaitOne(Timeout).Should().BeTrue(); repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); repositoryManagerListener.Received().CurrentBranchUpdated(Args.NullableConfigBranch, Args.NullableConfigRemote); From 8ac24f5b06945266f861c28cbb0e5b639dc97352 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Tue, 6 Feb 2018 13:16:35 +0100 Subject: [PATCH 0139/1008] Make sure finally always gets called --- src/GitHub.Api/Tasks/TaskBase.cs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index ed01ff7ee..2733b9089 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -213,14 +213,17 @@ public ITask Finally(T taskToContinueWith) return continuationOnAlways; } + /// + /// This does not set a dependency between the two tasks. Instead, + /// the Start method grabs the state of the previous task to pass on + /// to the next task via previousSuccess and previousException + /// + /// internal void SetFaultHandler(TaskBase handler) { - if (Task.Status == TaskStatus.Created) - this.continuationOnFailure = handler; - else - Task.ContinueWith(t => handler.Start(t), Token, - TaskContinuationOptions.OnlyOnFaulted, - TaskManager.GetScheduler(handler.Affinity)); + Task.ContinueWith(t => handler.Start(t), Token, + TaskContinuationOptions.OnlyOnFaulted, + TaskManager.GetScheduler(handler.Affinity)); DependsOn?.SetFaultHandler(handler); } @@ -260,6 +263,11 @@ protected void Run() } } + /// + /// Call this to run a task after another task is done, without + /// having them depend on each other + /// + /// protected void Start(Task task) { previousSuccess = task.Status == TaskStatus.RanToCompletion && task.Status != TaskStatus.Faulted; @@ -365,6 +373,11 @@ protected virtual void RaiseOnEnd() //Logger.Trace($"Finished {ToString()}"); } + protected void CallFinallyHandler() + { + finallyHandler?.Invoke(); + } + protected virtual bool RaiseFaultHandlers(Exception ex) { if (catchHandler == null) @@ -565,7 +578,10 @@ protected virtual void RaiseOnEnd(TResult result) { OnEnd?.Invoke(this, result); if (continuationOnSuccess == null && continuationOnFailure == null && continuationOnAlways == null) + { finallyHandler?.Invoke(result); + CallFinallyHandler(); + } //Logger.Trace($"Finished {ToString()} {result}"); } From ae352efb7cbb62669954ebf00f5d912be003c06a Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Tue, 6 Feb 2018 13:16:44 +0100 Subject: [PATCH 0140/1008] Add smarter logging to tests --- .../Events/RepositoryManagerTests.cs | 113 ++++++++++++++---- 1 file changed, 91 insertions(+), 22 deletions(-) diff --git a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs index 0d5a1af24..440ea99c9 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using System.Runtime.CompilerServices; using FluentAssertions; using GitHub.Unity; using NSubstitute; @@ -8,6 +10,7 @@ using TestUtils; using TestUtils.Events; using System.Threading.Tasks; +using GitHub.Logging; namespace IntegrationTests { @@ -23,10 +26,38 @@ public override void OnSetup() repositoryManagerEvents = new RepositoryManagerEvents(); } + private void StartTest(out Stopwatch watch, out ILogging logger, [CallerMemberName] string testName = "test") + { + watch = new Stopwatch(); + logger = LogHelper.GetLogger(testName); + logger.Trace("Starting test"); + } + + private void EndTest(ILogging logger) + { + logger.Trace("Ending test"); + } + + private void StartTrackTime(Stopwatch watch, ILogging logger, string message = "") + { + if (!String.IsNullOrEmpty(message)) + logger.Trace(message); + watch.Reset(); + watch.Start(); + } + + private void StopTrackTimeAndLog(Stopwatch watch, ILogging logger) + { + watch.Stop(); + logger.Trace($"Time: {watch.ElapsedMilliseconds}"); + } + [Test] public void ShouldPerformBasicInitialize() { - Logger.Trace("Starting ShouldPerformBasicInitialize"); + Stopwatch watch = null; + ILogging logger = null; + StartTest(out watch, out logger); try { @@ -56,14 +87,16 @@ public void ShouldPerformBasicInitialize() } finally { - Logger.Trace("Ending ShouldPerformBasicInitialize"); + EndTest(logger); } } [Test] public async Task ShouldDetectFileChanges() { - Logger.Trace("Starting ShouldDetectFileChanges"); + Stopwatch watch = null; + ILogging logger = null; + StartTest(out watch, out logger); try { @@ -90,8 +123,13 @@ public async Task ShouldDetectFileChanges() await TaskManager.Wait(); + StartTrackTime(watch, logger, "RepositoryManager.WaitForEvents()"); RepositoryManager.WaitForEvents(); + StopTrackTimeAndLog(watch, logger); + + StartTrackTime(watch, logger, "repositoryManagerEvents.WaitForNotBusy()"); repositoryManagerEvents.WaitForNotBusy(); + StopTrackTimeAndLog(watch, logger); repositoryManagerEvents.GitStatusUpdated.WaitOne(Timeout).Should().BeTrue(); @@ -106,14 +144,16 @@ public async Task ShouldDetectFileChanges() } finally { - Logger.Trace("Ending ShouldDetectFileChanges"); + EndTest(logger); } } [Test] public async Task ShouldAddAndCommitFiles() { - Logger.Trace("Starting ShouldAddAndCommitFiles"); + Stopwatch watch = null; + ILogging logger = null; + StartTest(out watch, out logger); try { @@ -184,14 +224,16 @@ await RepositoryManager } finally { - Logger.Trace("Ending ShouldAddAndCommitFiles"); + EndTest(logger); } } [Test] public async Task ShouldAddAndCommitAllFiles() { - Logger.Trace("Starting ShouldAddAndCommitAllFiles"); + Stopwatch watch = null; + ILogging logger = null; + StartTest(out watch, out logger); try { @@ -221,8 +263,13 @@ public async Task ShouldAddAndCommitAllFiles() await TaskManager.Wait(); + StartTrackTime(watch, logger, "RepositoryManager.WaitForEvents()"); RepositoryManager.WaitForEvents(); + StopTrackTimeAndLog(watch, logger); + + StartTrackTime(watch, logger, "repositoryManagerEvents.WaitForNotBusy()"); repositoryManagerEvents.WaitForNotBusy(); + StopTrackTimeAndLog(watch, logger); repositoryManagerEvents.GitStatusUpdated.WaitOne(Timeout).Should().BeTrue(); @@ -238,13 +285,21 @@ public async Task ShouldAddAndCommitAllFiles() repositoryManagerListener.ClearReceivedCalls(); repositoryManagerEvents.Reset(); + StartTrackTime(watch, logger, "CommitAllFiles"); await RepositoryManager .CommitAllFiles("IntegrationTest Commit", string.Empty) .StartAsAsync(); + + StopTrackTimeAndLog(watch, logger); await TaskManager.Wait(); + StartTrackTime(watch, logger, "RepositoryManager.WaitForEvents()"); RepositoryManager.WaitForEvents(); + StopTrackTimeAndLog(watch, logger); + + StartTrackTime(watch, logger, "repositoryManagerEvents.WaitForNotBusy()"); repositoryManagerEvents.WaitForNotBusy(); + StopTrackTimeAndLog(watch, logger); repositoryManagerEvents.GitStatusUpdated.WaitOne(Timeout).Should().BeTrue(); repositoryManagerEvents.GitStatusUpdated.WaitOne(Timeout).Should().BeTrue(); @@ -262,14 +317,16 @@ await RepositoryManager } finally { - Logger.Trace("Ending ShouldAddAndCommitAllFiles"); + EndTest(logger); } } [Test] public async Task ShouldDetectBranchChange() { - Logger.Trace("Starting ShouldDetectBranchChange"); + Stopwatch watch = null; + ILogging logger = null; + StartTest(out watch, out logger); try { @@ -312,14 +369,16 @@ public async Task ShouldDetectBranchChange() } finally { - Logger.Trace("Ending ShouldDetectBranchChange"); + EndTest(logger); } } [Test] public async Task ShouldDetectBranchDelete() { - Logger.Trace("Starting ShouldDetectBranchDelete"); + Stopwatch watch = null; + ILogging logger = null; + StartTest(out watch, out logger); try { @@ -364,14 +423,16 @@ public async Task ShouldDetectBranchDelete() } finally { - Logger.Trace("Ending ShouldDetectBranchDelete"); + EndTest(logger); } } [Test] public async Task ShouldDetectBranchCreate() { - Logger.Trace("Starting ShouldDetectBranchCreate"); + Stopwatch watch = null; + ILogging logger = null; + StartTest(out watch, out logger); try { @@ -433,14 +494,16 @@ public async Task ShouldDetectBranchCreate() } finally { - Logger.Trace("Ending ShouldDetectBranchCreate"); + EndTest(logger); } } [Test] public async Task ShouldDetectChangesToRemotes() { - Logger.Trace("Starting ShouldDetectChangesToRemotes"); + Stopwatch watch = null; + ILogging logger = null; + StartTest(out watch, out logger); try { @@ -509,14 +572,16 @@ public async Task ShouldDetectChangesToRemotes() } finally { - Logger.Trace("Ending ShouldDetectChangesToRemotes"); + EndTest(logger); } } [Test] public async Task ShouldDetectChangesToRemotesWhenSwitchingBranches() { - Logger.Trace("Starting ShouldDetectChangesToRemotesWhenSwitchingBranches"); + Stopwatch watch = null; + ILogging logger = null; + StartTest(out watch, out logger); try { @@ -585,14 +650,16 @@ await RepositoryManager.SwitchBranch("branch2") } finally { - Logger.Trace("Ending ShouldDetectChangesToRemotesWhenSwitchingBranches"); + EndTest(logger); } } [Test] public async Task ShouldDetectGitPull() { - Logger.Trace("Starting ShouldDetectGitPull"); + Stopwatch watch = null; + ILogging logger = null; + StartTest(out watch, out logger); try { @@ -634,14 +701,16 @@ public async Task ShouldDetectGitPull() } finally { - Logger.Trace("Ending ShouldDetectGitPull"); + EndTest(logger); } } [Test] public async Task ShouldDetectGitFetch() { - Logger.Trace("Starting ShouldDetectGitFetch"); + Stopwatch watch = null; + ILogging logger = null; + StartTest(out watch, out logger); try { @@ -684,7 +753,7 @@ public async Task ShouldDetectGitFetch() } finally { - Logger.Trace("Ending ShouldDetectGitFetch"); + EndTest(logger); } } } From 9e526539c9d236a7cc5b87d8afc24783c9d76efa Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 15 Feb 2018 16:10:17 +0100 Subject: [PATCH 0141/1008] Add .editorconfig with whitespace definition --- .editorconfig | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..1252530c4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[*.cs] +indent_style = space +indent_size = 4 From 2be4f510efd09dde0afc31fc5654c7f350b49823 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 15 Feb 2018 16:11:21 +0100 Subject: [PATCH 0142/1008] Fix codeanalysis-debug.ruleset not working properly --- common/codeanalysis-debug.ruleset | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/codeanalysis-debug.ruleset b/common/codeanalysis-debug.ruleset index a14eb45ce..5aba57f2b 100644 --- a/common/codeanalysis-debug.ruleset +++ b/common/codeanalysis-debug.ruleset @@ -1,5 +1,5 @@  - + @@ -86,7 +86,6 @@ - From e6f0acfa50bc28b84f86f35fb7b3f44ed032c842 Mon Sep 17 00:00:00 2001 From: Mauro Palumbo Date: Mon, 16 Oct 2017 08:59:34 -0400 Subject: [PATCH 0143/1008] Initial implementation of discard (git checkout) functionality --- src/GitHub.Api/Git/GitClient.cs | 40 ++++++++++++- src/GitHub.Api/Git/IRepository.cs | 1 + src/GitHub.Api/Git/Repository.cs | 7 ++- src/GitHub.Api/Git/RepositoryManager.cs | 9 +++ src/GitHub.Api/Git/Tasks/GitCheckoutTask.cs | 36 +++++++++++ src/GitHub.Api/GitHub.Api.csproj | 1 + .../Events/RepositoryManagerTests.cs | 59 +++++++++++++++++++ 7 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 src/GitHub.Api/Git/Tasks/GitCheckoutTask.cs diff --git a/src/GitHub.Api/Git/GitClient.cs b/src/GitHub.Api/Git/GitClient.cs index b54b058ef..0e0f16c65 100644 --- a/src/GitHub.Api/Git/GitClient.cs +++ b/src/GitHub.Api/Git/GitClient.cs @@ -69,7 +69,12 @@ ITask Add(IList files, ITask AddAll(IOutputProcessor processor = null); - ITask Remove(IList files, + ITask Discard( IList files, + IOutputProcessor processor = null ); + + ITask DiscardAll( IOutputProcessor processor = null ); + + ITask Remove(IList files, IOutputProcessor processor = null); ITask AddAndCommit(IList files, string message, string body, @@ -365,7 +370,38 @@ public ITask Add(IList files, return last; } - public ITask Remove(IList files, + public ITask Discard( IList files, + IOutputProcessor processor = null ) + { + Logger.Trace("Checkout Files"); + + GitCheckoutTask last = null; + foreach( var batch in files.Spool( 5000 ) ) + { + var current = new GitCheckoutTask( batch, cancellationToken, processor ).Configure( processManager ); + if( last == null ) + { + last = current; + } + else + { + last.Then( current ); + last = current; + } + } + + return last; + } + + public ITask DiscardAll( IOutputProcessor processor = null ) + { + Logger.Trace( "Checkout all files" ); + + return new GitCheckoutTask( cancellationToken, processor ) + .Configure( processManager ); + } + + public ITask Remove(IList files, IOutputProcessor processor = null) { Logger.Trace("Remove"); diff --git a/src/GitHub.Api/Git/IRepository.cs b/src/GitHub.Api/Git/IRepository.cs index 9b4754d4a..ec999b4bc 100644 --- a/src/GitHub.Api/Git/IRepository.cs +++ b/src/GitHub.Api/Git/IRepository.cs @@ -18,6 +18,7 @@ public interface IRepository : IEquatable ITask Revert(string changeset); ITask RequestLock(string file); ITask ReleaseLock(string file, bool force); + ITask CheckoutFiles( List files ); void CheckLogChangedEvent(CacheUpdateEvent gitLogCacheUpdateEvent); void CheckStatusChangedEvent(CacheUpdateEvent cacheUpdateEvent); diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 3682a60d4..4e72d2192 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -112,6 +112,11 @@ public ITask ReleaseLock(string file, bool force) return repositoryManager.UnlockFile(file, force); } + public ITask CheckoutFiles( List files ) + { + return repositoryManager.CheckoutFiles( files ); + } + public void CheckLogChangedEvent(CacheUpdateEvent cacheUpdateEvent) { var managedCache = cacheContainer.GitLogCache; @@ -834,4 +839,4 @@ public string UpdatedTimeString private set { updatedTimeString = value; } } } -} +} \ No newline at end of file diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index e969f7f25..a60893d15 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -35,6 +35,7 @@ public interface IRepositoryManager : IDisposable ITask CreateBranch(string branch, string baseBranch); ITask LockFile(string file); ITask UnlockFile(string file, bool force); + ITask CheckoutFiles(List files); void UpdateGitLog(); void UpdateGitStatus(); void UpdateGitAheadBehindStatus(); @@ -284,6 +285,14 @@ public void UpdateGitStatus() }).Start(); } + public ITask CheckoutFiles( List files ) + { + var discard = GitClient.Discard(files); + discard.OnStart += t => IsBusy = true; + + return discard.Finally(() => IsBusy = false); + } + public void UpdateGitAheadBehindStatus() { ConfigBranch? configBranch; diff --git a/src/GitHub.Api/Git/Tasks/GitCheckoutTask.cs b/src/GitHub.Api/Git/Tasks/GitCheckoutTask.cs new file mode 100644 index 000000000..66e439da6 --- /dev/null +++ b/src/GitHub.Api/Git/Tasks/GitCheckoutTask.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace GitHub.Unity +{ + class GitCheckoutTask : ProcessTask + { + private const string TaskName = "git checkout"; + private readonly string arguments; + + public GitCheckoutTask( IEnumerable files, CancellationToken token, + IOutputProcessor processor = null ) : base(token, processor ?? new SimpleOutputProcessor()) + { + Guard.ArgumentNotNull( files, "files" ); + Name = TaskName; + + arguments = "checkout "; + arguments += " -- "; + + foreach( var file in files ) + { + arguments += " \"" + file.ToNPath().ToString( SlashMode.Forward ) + "\""; + } + } + + public GitCheckoutTask( CancellationToken token, + IOutputProcessor processor = null ) : base( token, processor ?? new SimpleOutputProcessor() ) + { + arguments = "checkout -- ."; + } + + public override string ProcessArguments { get { return arguments; } } + public override TaskAffinity Affinity { get { return TaskAffinity.Exclusive; } } + } +} \ No newline at end of file diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 72cacaedd..6b45e1234 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -100,6 +100,7 @@ + diff --git a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs index 2a8581320..700b1aae8 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -755,5 +755,64 @@ public async Task ShouldDetectGitFetch() EndTest(logger); } } + + + + [Test] + public async Task ShouldCheckoutFiles() + { + await Initialize( TestRepoMasterCleanSynchronized ); + + var repositoryManagerListener = Substitute.For(); + repositoryManagerListener.AttachListener( RepositoryManager, repositoryManagerEvents ); + + var expected = new GitStatus + { + Behind = 1, + LocalBranch = "master", + RemoteBranch = "origin/master", + Entries = + new List { + new GitStatusEntry("foobar.txt", TestRepoMasterCleanSynchronized.Combine("foobar.txt"), + "foobar.txt", GitFileStatus.None) + } + }; + + var result = new GitStatus(); + Environment.Repository.OnStatusUpdated += status => { result = status; }; + + var foobarTxt = TestRepoMasterCleanSynchronized.Combine( "foobar.txt" ); + foobarTxt.WriteAllText( "foobar" ); + + await TaskManager.Wait(); + RepositoryManager.WaitForEvents(); + WaitForNotBusy( repositoryManagerEvents, 1 ); + + repositoryManagerListener.Received().OnStatusUpdate( Args.GitStatus ); + repositoryManagerListener.DidNotReceive().OnActiveBranchChanged( Arg.Any() ); + repositoryManagerListener.DidNotReceive().OnActiveRemoteChanged( Arg.Any() ); + repositoryManagerListener.DidNotReceive().OnLocalBranchListChanged(); + repositoryManagerListener.DidNotReceive().OnRemoteBranchListChanged(); + repositoryManagerListener.Received().OnIsBusyChanged( Args.Bool ); + repositoryManagerListener.DidNotReceive().OnLocksUpdated( Args.EnumerableGitLock ); + + await RepositoryManager.CheckoutFiles( new List() { "foobar.txt" } ) + .StartAsAsync(); + + await TaskManager.Wait(); + RepositoryManager.WaitForEvents(); + WaitForNotBusy( repositoryManagerEvents, 1 ); + repositoryManagerEvents.OnStatusUpdate.WaitOne( TimeSpan.FromSeconds( 1 ) ); + + repositoryManagerListener.Received().OnStatusUpdate( Args.GitStatus ); + repositoryManagerListener.DidNotReceive().OnActiveBranchChanged( Arg.Any() ); + repositoryManagerListener.DidNotReceive().OnActiveRemoteChanged( Arg.Any() ); + repositoryManagerListener.DidNotReceive().OnLocalBranchListChanged(); + repositoryManagerListener.DidNotReceive().OnRemoteBranchListChanged(); + repositoryManagerListener.Received().OnIsBusyChanged( Args.Bool ); + repositoryManagerListener.DidNotReceive().OnLocksUpdated( Args.EnumerableGitLock ); + + result.AssertEqual( expected ); + } } } From 26aa280ba05daab252f52ba49ae5ab8ba466ea3a Mon Sep 17 00:00:00 2001 From: Mauro Palumbo Date: Tue, 17 Oct 2017 10:11:38 +0200 Subject: [PATCH 0144/1008] changed expected status in Checkout unit test --- 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 700b1aae8..d9f962e69 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -774,7 +774,7 @@ public async Task ShouldCheckoutFiles() Entries = new List { new GitStatusEntry("foobar.txt", TestRepoMasterCleanSynchronized.Combine("foobar.txt"), - "foobar.txt", GitFileStatus.None) + "foobar.txt", GitFileStatus.Untracked) } }; From 67ed791cc3be9f1f8bb442aca7f86ac0807d0b81 Mon Sep 17 00:00:00 2001 From: Mauro Palumbo Date: Wed, 18 Oct 2017 14:43:42 +0200 Subject: [PATCH 0145/1008] Added repositoryManagerListener reset in Checkout test --- src/tests/IntegrationTests/Events/RepositoryManagerTests.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs index d9f962e69..ac4dba20e 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -813,6 +813,9 @@ public async Task ShouldCheckoutFiles() repositoryManagerListener.DidNotReceive().OnLocksUpdated( Args.EnumerableGitLock ); result.AssertEqual( expected ); - } + + repositoryManagerListener.ClearReceivedCalls(); + repositoryManagerEvents.Reset(); + } } } From dcf27c90e2b272001914afc7dd8c6979dc237522 Mon Sep 17 00:00:00 2001 From: Mauro Palumbo Date: Thu, 19 Oct 2017 10:09:42 +0200 Subject: [PATCH 0146/1008] Styling fixes --- src/GitHub.Api/Git/GitClient.cs | 72 ++++++------ src/GitHub.Api/Git/IRepository.cs | 2 +- src/GitHub.Api/Git/Repository.cs | 8 +- src/GitHub.Api/Git/RepositoryManager.cs | 14 +-- src/GitHub.Api/Git/Tasks/GitCheckoutTask.cs | 48 ++++---- .../Events/RepositoryManagerTests.cs | 110 +++++++++--------- 6 files changed, 127 insertions(+), 127 deletions(-) diff --git a/src/GitHub.Api/Git/GitClient.cs b/src/GitHub.Api/Git/GitClient.cs index 0e0f16c65..f5ac5d9c5 100644 --- a/src/GitHub.Api/Git/GitClient.cs +++ b/src/GitHub.Api/Git/GitClient.cs @@ -69,12 +69,12 @@ ITask Add(IList files, ITask AddAll(IOutputProcessor processor = null); - ITask Discard( IList files, - IOutputProcessor processor = null ); + ITask Discard(IList files, + IOutputProcessor processor = null); - ITask DiscardAll( IOutputProcessor processor = null ); + ITask DiscardAll(IOutputProcessor processor = null); - ITask Remove(IList files, + ITask Remove(IList files, IOutputProcessor processor = null); ITask AddAndCommit(IList files, string message, string body, @@ -370,38 +370,38 @@ public ITask Add(IList files, return last; } - public ITask Discard( IList files, - IOutputProcessor processor = null ) - { - Logger.Trace("Checkout Files"); - - GitCheckoutTask last = null; - foreach( var batch in files.Spool( 5000 ) ) - { - var current = new GitCheckoutTask( batch, cancellationToken, processor ).Configure( processManager ); - if( last == null ) - { - last = current; - } - else - { - last.Then( current ); - last = current; - } - } - - return last; - } - - public ITask DiscardAll( IOutputProcessor processor = null ) - { - Logger.Trace( "Checkout all files" ); - - return new GitCheckoutTask( cancellationToken, processor ) - .Configure( processManager ); - } - - public ITask Remove(IList files, + public ITask Discard( IList files, + IOutputProcessor processor = null) + { + Logger.Trace("Checkout Files"); + + GitCheckoutTask last = null; + foreach (var batch in files.Spool(5000)) + { + var current = new GitCheckoutTask(batch, cancellationToken, processor).Configure(processManager); + if (last == null) + { + last = current; + } + else + { + last.Then(current); + last = current; + } + } + + return last; + } + + public ITask DiscardAll(IOutputProcessor processor = null) + { + Logger.Trace("Checkout all files"); + + return new GitCheckoutTask(cancellationToken, processor) + .Configure(processManager); + } + + public ITask Remove(IList files, IOutputProcessor processor = null) { Logger.Trace("Remove"); diff --git a/src/GitHub.Api/Git/IRepository.cs b/src/GitHub.Api/Git/IRepository.cs index ec999b4bc..7b9501e25 100644 --- a/src/GitHub.Api/Git/IRepository.cs +++ b/src/GitHub.Api/Git/IRepository.cs @@ -18,7 +18,7 @@ public interface IRepository : IEquatable ITask Revert(string changeset); ITask RequestLock(string file); ITask ReleaseLock(string file, bool force); - ITask CheckoutFiles( List files ); + ITask CheckoutFiles(List files); void CheckLogChangedEvent(CacheUpdateEvent gitLogCacheUpdateEvent); void CheckStatusChangedEvent(CacheUpdateEvent cacheUpdateEvent); diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 4e72d2192..580a8b868 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -112,10 +112,10 @@ public ITask ReleaseLock(string file, bool force) return repositoryManager.UnlockFile(file, force); } - public ITask CheckoutFiles( List files ) - { - return repositoryManager.CheckoutFiles( files ); - } + public ITask CheckoutFiles(List files) + { + return repositoryManager.CheckoutFiles(files); + } public void CheckLogChangedEvent(CacheUpdateEvent cacheUpdateEvent) { diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index a60893d15..b9fed4e64 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -35,7 +35,7 @@ public interface IRepositoryManager : IDisposable ITask CreateBranch(string branch, string baseBranch); ITask LockFile(string file); ITask UnlockFile(string file, bool force); - ITask CheckoutFiles(List files); + ITask CheckoutFiles(List files); void UpdateGitLog(); void UpdateGitStatus(); void UpdateGitAheadBehindStatus(); @@ -285,13 +285,13 @@ public void UpdateGitStatus() }).Start(); } - public ITask CheckoutFiles( List files ) - { - var discard = GitClient.Discard(files); - discard.OnStart += t => IsBusy = true; + public ITask CheckoutFiles(List files) + { + var discard = GitClient.Discard(files); + discard.OnStart += t => IsBusy = true; - return discard.Finally(() => IsBusy = false); - } + return discard.Finally(() => IsBusy = false); + } public void UpdateGitAheadBehindStatus() { diff --git a/src/GitHub.Api/Git/Tasks/GitCheckoutTask.cs b/src/GitHub.Api/Git/Tasks/GitCheckoutTask.cs index 66e439da6..f64c89130 100644 --- a/src/GitHub.Api/Git/Tasks/GitCheckoutTask.cs +++ b/src/GitHub.Api/Git/Tasks/GitCheckoutTask.cs @@ -4,33 +4,33 @@ namespace GitHub.Unity { - class GitCheckoutTask : ProcessTask - { - private const string TaskName = "git checkout"; - private readonly string arguments; + class GitCheckoutTask : ProcessTask + { + private const string TaskName = "git checkout"; + private readonly string arguments; - public GitCheckoutTask( IEnumerable files, CancellationToken token, - IOutputProcessor processor = null ) : base(token, processor ?? new SimpleOutputProcessor()) - { - Guard.ArgumentNotNull( files, "files" ); - Name = TaskName; + public GitCheckoutTask(IEnumerable files, CancellationToken token, + IOutputProcessor processor = null) : base(token, processor ?? new SimpleOutputProcessor()) + { + Guard.ArgumentNotNull(files, "files"); + Name = TaskName; - arguments = "checkout "; - arguments += " -- "; + arguments = "checkout "; + arguments += " -- "; - foreach( var file in files ) - { - arguments += " \"" + file.ToNPath().ToString( SlashMode.Forward ) + "\""; - } - } + foreach (var file in files) + { + arguments += " \"" + file.ToNPath().ToString(SlashMode.Forward) + "\""; + } + } - public GitCheckoutTask( CancellationToken token, - IOutputProcessor processor = null ) : base( token, processor ?? new SimpleOutputProcessor() ) - { - arguments = "checkout -- ."; - } + public GitCheckoutTask(CancellationToken token, + IOutputProcessor processor = null) : base(token, processor ?? new SimpleOutputProcessor()) + { + arguments = "checkout -- ."; + } - public override string ProcessArguments { get { return arguments; } } - public override TaskAffinity Affinity { get { return TaskAffinity.Exclusive; } } - } + public override string ProcessArguments { get { return arguments; } } + public override TaskAffinity Affinity { get { return TaskAffinity.Exclusive; } } + } } \ No newline at end of file diff --git a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs index ac4dba20e..e15d890fa 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -758,61 +758,61 @@ public async Task ShouldDetectGitFetch() - [Test] - public async Task ShouldCheckoutFiles() - { - await Initialize( TestRepoMasterCleanSynchronized ); - - var repositoryManagerListener = Substitute.For(); - repositoryManagerListener.AttachListener( RepositoryManager, repositoryManagerEvents ); - - var expected = new GitStatus - { - Behind = 1, - LocalBranch = "master", - RemoteBranch = "origin/master", - Entries = - new List { - new GitStatusEntry("foobar.txt", TestRepoMasterCleanSynchronized.Combine("foobar.txt"), - "foobar.txt", GitFileStatus.Untracked) - } - }; - - var result = new GitStatus(); - Environment.Repository.OnStatusUpdated += status => { result = status; }; - - var foobarTxt = TestRepoMasterCleanSynchronized.Combine( "foobar.txt" ); - foobarTxt.WriteAllText( "foobar" ); - - await TaskManager.Wait(); - RepositoryManager.WaitForEvents(); - WaitForNotBusy( repositoryManagerEvents, 1 ); - - repositoryManagerListener.Received().OnStatusUpdate( Args.GitStatus ); - repositoryManagerListener.DidNotReceive().OnActiveBranchChanged( Arg.Any() ); - repositoryManagerListener.DidNotReceive().OnActiveRemoteChanged( Arg.Any() ); - repositoryManagerListener.DidNotReceive().OnLocalBranchListChanged(); - repositoryManagerListener.DidNotReceive().OnRemoteBranchListChanged(); - repositoryManagerListener.Received().OnIsBusyChanged( Args.Bool ); - repositoryManagerListener.DidNotReceive().OnLocksUpdated( Args.EnumerableGitLock ); - - await RepositoryManager.CheckoutFiles( new List() { "foobar.txt" } ) - .StartAsAsync(); - - await TaskManager.Wait(); - RepositoryManager.WaitForEvents(); - WaitForNotBusy( repositoryManagerEvents, 1 ); - repositoryManagerEvents.OnStatusUpdate.WaitOne( TimeSpan.FromSeconds( 1 ) ); - - repositoryManagerListener.Received().OnStatusUpdate( Args.GitStatus ); - repositoryManagerListener.DidNotReceive().OnActiveBranchChanged( Arg.Any() ); - repositoryManagerListener.DidNotReceive().OnActiveRemoteChanged( Arg.Any() ); - repositoryManagerListener.DidNotReceive().OnLocalBranchListChanged(); - repositoryManagerListener.DidNotReceive().OnRemoteBranchListChanged(); - repositoryManagerListener.Received().OnIsBusyChanged( Args.Bool ); - repositoryManagerListener.DidNotReceive().OnLocksUpdated( Args.EnumerableGitLock ); - - result.AssertEqual( expected ); + [Test] + public async Task ShouldCheckoutFiles() + { + await Initialize(TestRepoMasterCleanSynchronized); + + var repositoryManagerListener = Substitute.For(); + repositoryManagerListener.AttachListener(RepositoryManager, repositoryManagerEvents); + + var expected = new GitStatus + { + Behind = 1, + LocalBranch = "master", + RemoteBranch = "origin/master", + Entries = + new List { + new GitStatusEntry("foobar.txt", TestRepoMasterCleanSynchronized.Combine("foobar.txt"), + "foobar.txt", GitFileStatus.Untracked) + } + }; + + var result = new GitStatus(); + Environment.Repository.OnStatusUpdated += status => { result = status; }; + + var foobarTxt = TestRepoMasterCleanSynchronized.Combine("foobar.txt"); + foobarTxt.WriteAllText("foobar"); + + await TaskManager.Wait(); + RepositoryManager.WaitForEvents(); + WaitForNotBusy(repositoryManagerEvents, 1); + + repositoryManagerListener.Received().OnStatusUpdate(Args.GitStatus); + repositoryManagerListener.DidNotReceive().OnActiveBranchChanged(Arg.Any()); + repositoryManagerListener.DidNotReceive().OnActiveRemoteChanged(Arg.Any()); + repositoryManagerListener.DidNotReceive().OnLocalBranchListChanged(); + repositoryManagerListener.DidNotReceive().OnRemoteBranchListChanged(); + repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); + repositoryManagerListener.DidNotReceive().OnLocksUpdated(Args.EnumerableGitLock); + + await RepositoryManager.CheckoutFiles(new List() { "foobar.txt" }) + .StartAsAsync(); + + await TaskManager.Wait(); + RepositoryManager.WaitForEvents(); + WaitForNotBusy(repositoryManagerEvents, 1); + repositoryManagerEvents.OnStatusUpdate.WaitOne(TimeSpan.FromSeconds(1)); + + repositoryManagerListener.Received().OnStatusUpdate(Args.GitStatus); + repositoryManagerListener.DidNotReceive().OnActiveBranchChanged(Arg.Any()); + repositoryManagerListener.DidNotReceive().OnActiveRemoteChanged(Arg.Any()); + repositoryManagerListener.DidNotReceive().OnLocalBranchListChanged(); + repositoryManagerListener.DidNotReceive().OnRemoteBranchListChanged(); + repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); + repositoryManagerListener.DidNotReceive().OnLocksUpdated(Args.EnumerableGitLock); + + result.AssertEqual(expected); repositoryManagerListener.ClearReceivedCalls(); repositoryManagerEvents.Reset(); From 23c642a9bdaa77043dbf45abd511e107bc4b0df3 Mon Sep 17 00:00:00 2001 From: Mauro Palumbo Date: Wed, 25 Oct 2017 13:57:26 +0200 Subject: [PATCH 0147/1008] Renamed IRepository::CheckoutFiles to DiscardChanges to better reflect its functionality --- src/GitHub.Api/Git/IRepository.cs | 4 ++-- src/GitHub.Api/Git/Repository.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/GitHub.Api/Git/IRepository.cs b/src/GitHub.Api/Git/IRepository.cs index 7b9501e25..95f35d3ba 100644 --- a/src/GitHub.Api/Git/IRepository.cs +++ b/src/GitHub.Api/Git/IRepository.cs @@ -4,7 +4,7 @@ namespace GitHub.Unity { /// - /// Represents a repository, either local or retreived via the GitHub API. + /// Represents a repository, either local or retrieved via the GitHub API. /// public interface IRepository : IEquatable { @@ -18,7 +18,7 @@ public interface IRepository : IEquatable ITask Revert(string changeset); ITask RequestLock(string file); ITask ReleaseLock(string file, bool force); - ITask CheckoutFiles(List files); + ITask DiscardChanges(List files); void CheckLogChangedEvent(CacheUpdateEvent gitLogCacheUpdateEvent); void CheckStatusChangedEvent(CacheUpdateEvent cacheUpdateEvent); diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 580a8b868..903d222fa 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -112,7 +112,7 @@ public ITask ReleaseLock(string file, bool force) return repositoryManager.UnlockFile(file, force); } - public ITask CheckoutFiles(List files) + public ITask DiscardChanges(List files) { return repositoryManager.CheckoutFiles(files); } From 618e9dc7fd30588ab837a640f7bd09bfaa332fb0 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 13 Dec 2017 15:15:02 -0500 Subject: [PATCH 0148/1008] Removing integration test --- src/GitHub.Api/Git/GitClient.cs | 2 +- .../Events/RepositoryManagerTests.cs | 62 ------------------- 2 files changed, 1 insertion(+), 63 deletions(-) diff --git a/src/GitHub.Api/Git/GitClient.cs b/src/GitHub.Api/Git/GitClient.cs index f5ac5d9c5..3c61bfd33 100644 --- a/src/GitHub.Api/Git/GitClient.cs +++ b/src/GitHub.Api/Git/GitClient.cs @@ -370,7 +370,7 @@ public ITask Add(IList files, return last; } - public ITask Discard( IList files, + public ITask Discard( IList files, IOutputProcessor processor = null) { Logger.Trace("Checkout Files"); diff --git a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs index e15d890fa..2a8581320 100644 --- a/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs +++ b/src/tests/IntegrationTests/Events/RepositoryManagerTests.cs @@ -755,67 +755,5 @@ public async Task ShouldDetectGitFetch() EndTest(logger); } } - - - - [Test] - public async Task ShouldCheckoutFiles() - { - await Initialize(TestRepoMasterCleanSynchronized); - - var repositoryManagerListener = Substitute.For(); - repositoryManagerListener.AttachListener(RepositoryManager, repositoryManagerEvents); - - var expected = new GitStatus - { - Behind = 1, - LocalBranch = "master", - RemoteBranch = "origin/master", - Entries = - new List { - new GitStatusEntry("foobar.txt", TestRepoMasterCleanSynchronized.Combine("foobar.txt"), - "foobar.txt", GitFileStatus.Untracked) - } - }; - - var result = new GitStatus(); - Environment.Repository.OnStatusUpdated += status => { result = status; }; - - var foobarTxt = TestRepoMasterCleanSynchronized.Combine("foobar.txt"); - foobarTxt.WriteAllText("foobar"); - - await TaskManager.Wait(); - RepositoryManager.WaitForEvents(); - WaitForNotBusy(repositoryManagerEvents, 1); - - repositoryManagerListener.Received().OnStatusUpdate(Args.GitStatus); - repositoryManagerListener.DidNotReceive().OnActiveBranchChanged(Arg.Any()); - repositoryManagerListener.DidNotReceive().OnActiveRemoteChanged(Arg.Any()); - repositoryManagerListener.DidNotReceive().OnLocalBranchListChanged(); - repositoryManagerListener.DidNotReceive().OnRemoteBranchListChanged(); - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.DidNotReceive().OnLocksUpdated(Args.EnumerableGitLock); - - await RepositoryManager.CheckoutFiles(new List() { "foobar.txt" }) - .StartAsAsync(); - - await TaskManager.Wait(); - RepositoryManager.WaitForEvents(); - WaitForNotBusy(repositoryManagerEvents, 1); - repositoryManagerEvents.OnStatusUpdate.WaitOne(TimeSpan.FromSeconds(1)); - - repositoryManagerListener.Received().OnStatusUpdate(Args.GitStatus); - repositoryManagerListener.DidNotReceive().OnActiveBranchChanged(Arg.Any()); - repositoryManagerListener.DidNotReceive().OnActiveRemoteChanged(Arg.Any()); - repositoryManagerListener.DidNotReceive().OnLocalBranchListChanged(); - repositoryManagerListener.DidNotReceive().OnRemoteBranchListChanged(); - repositoryManagerListener.Received().OnIsBusyChanged(Args.Bool); - repositoryManagerListener.DidNotReceive().OnLocksUpdated(Args.EnumerableGitLock); - - result.AssertEqual(expected); - - repositoryManagerListener.ClearReceivedCalls(); - repositoryManagerEvents.Reset(); - } } } From 5a478a152004e0c64cf52119b2cb304fdcddcc9c Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 18 Dec 2017 22:24:16 -0500 Subject: [PATCH 0149/1008] Functionality to revert and delete --- .../Application/ApplicationManagerBase.cs | 2 +- src/GitHub.Api/Git/IRepository.cs | 1 + src/GitHub.Api/Git/Repository.cs | 5 ++ src/GitHub.Api/Git/RepositoryManager.cs | 24 +++++++-- src/GitHub.Api/GitHub.Api.csproj | 1 + .../Platform/DeleteFilesExecTask.cs | 31 +++++++++++ .../Editor/GitHub.Unity/UI/ChangesView.cs | 53 ++++++++++++++++++- .../BaseGitEnvironmentTest.cs | 3 +- 8 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 src/GitHub.Api/Platform/DeleteFilesExecTask.cs diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 61894c369..d6ca6f2fb 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -128,7 +128,7 @@ public void RestartRepository() { if (Environment.RepositoryPath != null) { - repositoryManager = Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, Environment.RepositoryPath); + repositoryManager = Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, ProcessManager, Environment.RepositoryPath); repositoryManager.Initialize(); Environment.Repository.Initialize(repositoryManager); repositoryManager.Start(); diff --git a/src/GitHub.Api/Git/IRepository.cs b/src/GitHub.Api/Git/IRepository.cs index 95f35d3ba..8ca785412 100644 --- a/src/GitHub.Api/Git/IRepository.cs +++ b/src/GitHub.Api/Git/IRepository.cs @@ -19,6 +19,7 @@ public interface IRepository : IEquatable ITask RequestLock(string file); ITask ReleaseLock(string file, bool force); ITask DiscardChanges(List files); + ITask DeleteFiles(List list); void CheckLogChangedEvent(CacheUpdateEvent gitLogCacheUpdateEvent); void CheckStatusChangedEvent(CacheUpdateEvent cacheUpdateEvent); diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 903d222fa..610aae9cc 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -117,6 +117,11 @@ public ITask DiscardChanges(List files) return repositoryManager.CheckoutFiles(files); } + public ITask DeleteFiles(List list) + { + return repositoryManager.DeleteFiles(list); + } + public void CheckLogChangedEvent(CacheUpdateEvent cacheUpdateEvent) { var managedCache = cacheContainer.GitLogCache; diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index b9fed4e64..926749808 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -36,6 +36,7 @@ public interface IRepositoryManager : IDisposable ITask LockFile(string file); ITask UnlockFile(string file, bool force); ITask CheckoutFiles(List files); + ITask DeleteFiles(List list); void UpdateGitLog(); void UpdateGitStatus(); void UpdateGitAheadBehindStatus(); @@ -97,6 +98,7 @@ class RepositoryManager : IRepositoryManager { private readonly IGitConfig config; private readonly IGitClient gitClient; + private readonly IProcessManager processManager; private readonly IRepositoryPathConfiguration repositoryPaths; private readonly IRepositoryWatcher watcher; @@ -113,18 +115,19 @@ class RepositoryManager : IRepositoryManager public RepositoryManager(IGitConfig gitConfig, IRepositoryWatcher repositoryWatcher, IGitClient gitClient, + IProcessManager processManager, IRepositoryPathConfiguration repositoryPaths) { this.repositoryPaths = repositoryPaths; this.gitClient = gitClient; + this.processManager = processManager; this.watcher = repositoryWatcher; this.config = gitConfig; SetupWatcher(); } - public static RepositoryManager CreateInstance(IPlatform platform, ITaskManager taskManager, - IGitClient gitClient, NPath repositoryRoot) + public static RepositoryManager CreateInstance(IPlatform platform, ITaskManager taskManager, IGitClient gitClient, IProcessManager processManager, NPath repositoryRoot) { var repositoryPathConfiguration = new RepositoryPathConfiguration(repositoryRoot); string filePath = repositoryPathConfiguration.DotGitConfig; @@ -133,7 +136,7 @@ public static RepositoryManager CreateInstance(IPlatform platform, ITaskManager var repositoryWatcher = new RepositoryWatcher(platform, repositoryPathConfiguration, taskManager.Token); return new RepositoryManager(gitConfig, repositoryWatcher, - gitClient, repositoryPathConfiguration); + gitClient, processManager, repositoryPathConfiguration); } public void Initialize() @@ -293,6 +296,21 @@ public ITask CheckoutFiles(List files) return discard.Finally(() => IsBusy = false); } + public ITask DeleteFiles(List list) + { + ITask> task = new DeleteFilesExecTask(list.ToArray(), CancellationToken.None) + .Configure(processManager); + + task = HookupHandlers(task, true, true); + + var @finally = task.Finally((b, exception, arg3) => { + Logger.Trace("Delete Files success:{0} output: {1}", b, arg3 != null ? string.Join(",", arg3.ToArray()) : "[NULL]"); + }); + + return @finally + .Start(); + } + public void UpdateGitAheadBehindStatus() { ConfigBranch? configBranch; diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 6b45e1234..b5d01518c 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -147,6 +147,7 @@ + diff --git a/src/GitHub.Api/Platform/DeleteFilesExecTask.cs b/src/GitHub.Api/Platform/DeleteFilesExecTask.cs new file mode 100644 index 000000000..e63263a74 --- /dev/null +++ b/src/GitHub.Api/Platform/DeleteFilesExecTask.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Threading; + +namespace GitHub.Unity +{ + class DeleteFilesExecTask : ProcessTask> + { + private readonly string arguments; + + public DeleteFilesExecTask(string[] files, CancellationToken token) + : base(token, new SimpleListOutputProcessor()) + { + Name = DefaultEnvironment.OnWindows ? "cmd" : "rm"; + + var fileString = string.Join(" ", files); + if (DefaultEnvironment.OnWindows) + { + arguments = $"/c \"del {fileString}\""; + } + else + { + arguments = fileString; + } + + } + + public override string ProcessName { get { return Name; } } + public override string ProcessArguments { get { return arguments; } } + public override TaskAffinity Affinity { get { return TaskAffinity.Concurrent; } } + } +} \ No newline at end of file diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs index 0acdfb56b..51c6138af 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs @@ -23,6 +23,9 @@ class ChangesView : Subview [NonSerialized] private bool currentLocksHasUpdate; [NonSerialized] private bool isBusy; + [NonSerialized] private GUIContent revertGuiContent; + [NonSerialized] private GUIContent deleteGuiContent; + [SerializeField] private string commitBody = ""; [SerializeField] private string commitMessage = ""; [SerializeField] private string currentBranch = "[unknown]"; @@ -143,7 +146,10 @@ private void OnTreeGUI(Rect rect) var treeRenderRect = treeChanges.Render(rect, treeScroll, node => { }, node => { }, - node => { }); + node => { + var menu = CreateContextMenu(node); + menu.ShowAsContext(); + }); if (treeChanges.RequiresRepaint) Redraw(); @@ -152,6 +158,51 @@ private void OnTreeGUI(Rect rect) } } + private GenericMenu CreateContextMenu(ChangesTreeNode node) + { + var genericMenu = new GenericMenu(); + var canRevert = false; + var canDelete = false; + + if (!node.isFolder) + { + canRevert = node.GitFileStatus == GitFileStatus.Added + || node.GitFileStatus == GitFileStatus.Modified + || node.GitFileStatus == GitFileStatus.Deleted + || node.GitFileStatus == GitFileStatus.Renamed; + + canDelete = node.GitFileStatus == GitFileStatus.Untracked; + } + + if (canRevert) + { + if (revertGuiContent == null) + { + revertGuiContent = new GUIContent("Revert"); + } + + genericMenu.AddItem(revertGuiContent, false, () => { + Repository.DiscardChanges(new List { node.Path }) + .Start(); + }); + } + + if (canDelete) + { + if (deleteGuiContent == null) + { + deleteGuiContent = new GUIContent("Delete"); + } + + genericMenu.AddItem(deleteGuiContent, false, () => { + Repository.DeleteFiles(new List { node.Path }) + .Start(); + }); + } + + return genericMenu; + } + private void RepositoryOnStatusEntriesChanged(CacheUpdateEvent cacheUpdateEvent) { if (!lastStatusEntriesChangedEvent.Equals(cacheUpdateEvent)) diff --git a/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs b/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs index 522bdef8e..e9ef4d1c5 100644 --- a/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs +++ b/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs @@ -14,8 +14,7 @@ protected IEnvironment Initialize(NPath repoPath, NPath environmentPath = null, { InitializePlatform(repoPath, environmentPath, enableEnvironmentTrace); - var repositoryManager = - GitHub.Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, repoPath); + var repositoryManager = GitHub.Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, ProcessManager, repoPath); onRepositoryManagerCreated?.Invoke(repositoryManager); RepositoryManager = repositoryManager; From 2942e249c4658efbc1e13ec57183efb7eb5d2c7d Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 31 Jan 2018 13:15:44 -0500 Subject: [PATCH 0150/1008] Doing delete with .Net is a whole lot faster --- .../Application/ApplicationManagerBase.cs | 2 +- src/GitHub.Api/Git/RepositoryManager.cs | 26 +++++++++------- src/GitHub.Api/GitHub.Api.csproj | 1 - .../Platform/DeleteFilesExecTask.cs | 31 ------------------- .../BaseGitEnvironmentTest.cs | 2 +- 5 files changed, 16 insertions(+), 46 deletions(-) delete mode 100644 src/GitHub.Api/Platform/DeleteFilesExecTask.cs diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index d6ca6f2fb..249f4e237 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -128,7 +128,7 @@ public void RestartRepository() { if (Environment.RepositoryPath != null) { - repositoryManager = Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, ProcessManager, Environment.RepositoryPath); + repositoryManager = Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, ProcessManager, Environment.RepositoryPath, Environment.FileSystem); repositoryManager.Initialize(); Environment.Repository.Initialize(repositoryManager); repositoryManager.Start(); diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index 926749808..d493d71b9 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -100,6 +100,7 @@ class RepositoryManager : IRepositoryManager private readonly IGitClient gitClient; private readonly IProcessManager processManager; private readonly IRepositoryPathConfiguration repositoryPaths; + private readonly IFileSystem fileSystem; private readonly IRepositoryWatcher watcher; private bool isBusy; @@ -116,9 +117,11 @@ class RepositoryManager : IRepositoryManager public RepositoryManager(IGitConfig gitConfig, IRepositoryWatcher repositoryWatcher, IGitClient gitClient, IProcessManager processManager, - IRepositoryPathConfiguration repositoryPaths) + IRepositoryPathConfiguration repositoryPaths, + IFileSystem fileSystem) { this.repositoryPaths = repositoryPaths; + this.fileSystem = fileSystem; this.gitClient = gitClient; this.processManager = processManager; this.watcher = repositoryWatcher; @@ -127,7 +130,7 @@ public RepositoryManager(IGitConfig gitConfig, SetupWatcher(); } - public static RepositoryManager CreateInstance(IPlatform platform, ITaskManager taskManager, IGitClient gitClient, IProcessManager processManager, NPath repositoryRoot) + public static RepositoryManager CreateInstance(IPlatform platform, ITaskManager taskManager, IGitClient gitClient, IProcessManager processManager, NPath repositoryRoot, IFileSystem fileSystem) { var repositoryPathConfiguration = new RepositoryPathConfiguration(repositoryRoot); string filePath = repositoryPathConfiguration.DotGitConfig; @@ -136,7 +139,7 @@ public static RepositoryManager CreateInstance(IPlatform platform, ITaskManager var repositoryWatcher = new RepositoryWatcher(platform, repositoryPathConfiguration, taskManager.Token); return new RepositoryManager(gitConfig, repositoryWatcher, - gitClient, processManager, repositoryPathConfiguration); + gitClient, processManager, repositoryPathConfiguration, fileSystem); } public void Initialize() @@ -298,17 +301,16 @@ public ITask CheckoutFiles(List files) public ITask DeleteFiles(List list) { - ITask> task = new DeleteFilesExecTask(list.ToArray(), CancellationToken.None) - .Configure(processManager); - - task = HookupHandlers(task, true, true); - - var @finally = task.Finally((b, exception, arg3) => { - Logger.Trace("Delete Files success:{0} output: {1}", b, arg3 != null ? string.Join(",", arg3.ToArray()) : "[NULL]"); + var delete = new ActionTask(CancellationToken.None, () => { + for (var index = 0; index < list.Count; index++) + { + fileSystem.FileDelete(list[index]); + } }); - return @finally - .Start(); + delete.OnStart += t => IsBusy = true; + + return delete.Finally(() => IsBusy = false); } public void UpdateGitAheadBehindStatus() diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index b5d01518c..6b45e1234 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -147,7 +147,6 @@ - diff --git a/src/GitHub.Api/Platform/DeleteFilesExecTask.cs b/src/GitHub.Api/Platform/DeleteFilesExecTask.cs deleted file mode 100644 index e63263a74..000000000 --- a/src/GitHub.Api/Platform/DeleteFilesExecTask.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections.Generic; -using System.Threading; - -namespace GitHub.Unity -{ - class DeleteFilesExecTask : ProcessTask> - { - private readonly string arguments; - - public DeleteFilesExecTask(string[] files, CancellationToken token) - : base(token, new SimpleListOutputProcessor()) - { - Name = DefaultEnvironment.OnWindows ? "cmd" : "rm"; - - var fileString = string.Join(" ", files); - if (DefaultEnvironment.OnWindows) - { - arguments = $"/c \"del {fileString}\""; - } - else - { - arguments = fileString; - } - - } - - public override string ProcessName { get { return Name; } } - public override string ProcessArguments { get { return arguments; } } - public override TaskAffinity Affinity { get { return TaskAffinity.Concurrent; } } - } -} \ No newline at end of file diff --git a/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs b/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs index e9ef4d1c5..c840f236c 100644 --- a/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs +++ b/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs @@ -14,7 +14,7 @@ protected IEnvironment Initialize(NPath repoPath, NPath environmentPath = null, { InitializePlatform(repoPath, environmentPath, enableEnvironmentTrace); - var repositoryManager = GitHub.Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, ProcessManager, repoPath); + var repositoryManager = GitHub.Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, ProcessManager, repoPath, Environment.FileSystem); onRepositoryManagerCreated?.Invoke(repositoryManager); RepositoryManager = repositoryManager; From 94f691f76ee77ff58cfab02123c9f070ff48db26 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 31 Jan 2018 18:09:34 -0500 Subject: [PATCH 0151/1008] Allowing RepositoryManager to control the process of discarding changes --- src/GitHub.Api/Git/IRepository.cs | 3 +- src/GitHub.Api/Git/Repository.cs | 9 +- src/GitHub.Api/Git/RepositoryManager.cs | 137 +++++++++++------- .../GitHub.Unity/UI/ChangesTreeControl.cs | 17 +-- .../Editor/GitHub.Unity/UI/ChangesView.cs | 30 +--- 5 files changed, 102 insertions(+), 94 deletions(-) diff --git a/src/GitHub.Api/Git/IRepository.cs b/src/GitHub.Api/Git/IRepository.cs index 8ca785412..83791f9f8 100644 --- a/src/GitHub.Api/Git/IRepository.cs +++ b/src/GitHub.Api/Git/IRepository.cs @@ -18,8 +18,7 @@ public interface IRepository : IEquatable ITask Revert(string changeset); ITask RequestLock(string file); ITask ReleaseLock(string file, bool force); - ITask DiscardChanges(List files); - ITask DeleteFiles(List list); + ITask DiscardChanges(List files); void CheckLogChangedEvent(CacheUpdateEvent gitLogCacheUpdateEvent); void CheckStatusChangedEvent(CacheUpdateEvent cacheUpdateEvent); diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 610aae9cc..68187ce70 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -112,14 +112,9 @@ public ITask ReleaseLock(string file, bool force) return repositoryManager.UnlockFile(file, force); } - public ITask DiscardChanges(List files) + public ITask DiscardChanges(List files) { - return repositoryManager.CheckoutFiles(files); - } - - public ITask DeleteFiles(List list) - { - return repositoryManager.DeleteFiles(list); + return repositoryManager.DiscardChanges(files); } public void CheckLogChangedEvent(CacheUpdateEvent cacheUpdateEvent) diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index d493d71b9..e1bb81c2b 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -35,8 +35,7 @@ public interface IRepositoryManager : IDisposable ITask CreateBranch(string branch, string baseBranch); ITask LockFile(string file); ITask UnlockFile(string file, bool force); - ITask CheckoutFiles(List files); - ITask DeleteFiles(List list); + ITask DiscardChanges(List files); void UpdateGitLog(); void UpdateGitStatus(); void UpdateGitAheadBehindStatus(); @@ -218,15 +217,13 @@ public ITask Revert(string changeset) public ITask RemoteAdd(string remote, string url) { var task = GitClient.RemoteAdd(remote, url); - task = HookupHandlers(task, true, false); - return task; + return HookupHandlers(task, true, false); } public ITask RemoteRemove(string remote) { var task = GitClient.RemoteRemove(remote); - task = HookupHandlers(task, true, false); - return task; + return HookupHandlers(task, true, false); } public ITask RemoteChange(string remote, string url) @@ -267,50 +264,86 @@ public ITask UnlockFile(string file, bool force) public void UpdateGitLog() { - var task = GitClient.Log(); - task = HookupHandlers(task, false, false); - task.Then((success, logEntries) => - { - if (success) + var task = GitClient + .Log() + .Then((success, logEntries) => { - GitLogUpdated?.Invoke(logEntries); - } - }).Start(); + if (success) + { + GitLogUpdated?.Invoke(logEntries); + } + }); + task = HookupHandlers(task, false, false); + task.Start(); } public void UpdateGitStatus() { - var task = GitClient.Status(); - task = HookupHandlers(task, true, false); - task.Then((success, status) => - { - if (success) + var task = GitClient + .Status() + .Then((success, status) => { - GitStatusUpdated?.Invoke(status); - } - }).Start(); + if (success) + { + GitStatusUpdated?.Invoke(status); + } + }); + task = HookupHandlers(task, true, false); + task.Start(); } - public ITask CheckoutFiles(List files) + public ITask DiscardChanges(List files) { - var discard = GitClient.Discard(files); - discard.OnStart += t => IsBusy = true; + var itemsToDelete = files + .Where(entry => entry.status == GitFileStatus.Added + || entry.status == GitFileStatus.Untracked) + .Select(entry => entry.path) + .ToArray(); - return discard.Finally(() => IsBusy = false); - } + ActionTask deleteItemsTask = null; + if (itemsToDelete.Any()) + { + deleteItemsTask = new ActionTask(CancellationToken.None, () => { + for (var index = 0; index < itemsToDelete.Length; index++) + { + var itemToDelete = itemsToDelete[index]; + fileSystem.FileDelete(itemToDelete); + } + }); + } - public ITask DeleteFiles(List list) - { - var delete = new ActionTask(CancellationToken.None, () => { - for (var index = 0; index < list.Count; index++) - { - fileSystem.FileDelete(list[index]); - } - }); + var itemsToRevert = files + .Where(entry => entry.status == GitFileStatus.Modified + || entry.status == GitFileStatus.Deleted + || entry.status == GitFileStatus.Renamed) + .Select(entry => entry.path) + .ToArray(); - delete.OnStart += t => IsBusy = true; + ITask gitDiscardTask = null; + if (itemsToRevert.Any()) + { + gitDiscardTask = GitClient.Discard(itemsToRevert); + } - return delete.Finally(() => IsBusy = false); + ITask task; + if(deleteItemsTask != null && gitDiscardTask != null) + { + task = deleteItemsTask.Then(gitDiscardTask); + } + else if (deleteItemsTask != null) + { + task = deleteItemsTask; + } + else if (gitDiscardTask != null) + { + task = gitDiscardTask; + } + else + { + throw new NotImplementedException(); + } + + return HookupHandlers(task, true, true); } public void UpdateGitAheadBehindStatus() @@ -324,15 +357,17 @@ public void UpdateGitAheadBehindStatus() var name = configBranch.Value.Name; var trackingName = configBranch.Value.IsTracking ? configBranch.Value.Remote.Value.Name + "/" + name : "[None]"; - var task = GitClient.AheadBehindStatus(name, trackingName); - task = HookupHandlers(task, true, false); - task.Then((success, status) => - { - if (success) + var task = GitClient + .AheadBehindStatus(name, trackingName) + .Then((success, status) => { - GitAheadBehindStatusUpdated?.Invoke(status); - } - }).Start(); + if (success) + { + GitAheadBehindStatusUpdated?.Invoke(status); + } + }); + task = HookupHandlers(task, true, false); + task.Start(); } else { @@ -353,9 +388,9 @@ public void UpdateLocks() }).Start(); } - private ITask HookupHandlers(ITask task, bool isExclusive, bool filesystemChangesExpected) + private ITask HookupHandlers(ITask task, bool isExclusive, bool filesystemChangesExpected) { - return new ActionTask(TaskManager.Instance.Token, () => { + return new ActionTask(CancellationToken.None, () => { if (isExclusive) { Logger.Trace("Starting Operation - Setting Busy Flag"); @@ -369,7 +404,7 @@ private ITask HookupHandlers(ITask task, bool isExclusive, bool filesys } }) .Then(task) - .Finally((success, exception, result) => { + .Finally((success, exception) => { if (filesystemChangesExpected) { Logger.Trace("Ended Operation - Enable Watcher"); @@ -382,12 +417,10 @@ private ITask HookupHandlers(ITask task, bool isExclusive, bool filesys IsBusy = false; } - if (success) + if (!success) { - return result; + throw exception; } - - throw exception; }); } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs index a648f9509..798244dc4 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs @@ -17,16 +17,16 @@ public class ChangesTreeNode : TreeNode public GitFileStatus gitFileStatus; public bool isLocked; + public GitStatusEntry GitStatusEntry { get; set; } + public string ProjectPath { - get { return projectPath; } - set { projectPath = value; } + get { return GitStatusEntry.projectPath; } } public GitFileStatus GitFileStatus { - get { return gitFileStatus; } - set { gitFileStatus = value; } + get { return GitStatusEntry.status; } } public bool IsLocked @@ -191,15 +191,13 @@ protected Texture GetNodeIconBadge(ChangesTreeNode node) protected override ChangesTreeNode CreateTreeNode(string path, string label, int level, bool isFolder, bool isActive, bool isHidden, bool isCollapsed, bool isChecked, GitStatusEntryTreeData? treeData) { - var gitFileStatus = GitFileStatus.None; - var projectPath = (string) null; + var gitStatusEntry = GitStatusEntry.Default; var isLocked = false; if (treeData.HasValue) { isLocked = treeData.Value.IsLocked; - gitFileStatus = treeData.Value.FileStatus; - projectPath = treeData.Value.ProjectPath; + gitStatusEntry = treeData.Value.GitStatusEntry; } var node = new ChangesTreeNode @@ -213,8 +211,7 @@ protected override ChangesTreeNode CreateTreeNode(string path, string label, int IsCollapsed = isCollapsed, TreeIsCheckable = IsCheckable, CheckState = isChecked ? CheckState.Checked : CheckState.Empty, - GitFileStatus = gitFileStatus, - ProjectPath = projectPath, + GitStatusEntry = gitStatusEntry, IsLocked = isLocked, }; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs index 51c6138af..c631fe3c4 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs @@ -24,7 +24,6 @@ class ChangesView : Subview [NonSerialized] private bool isBusy; [NonSerialized] private GUIContent revertGuiContent; - [NonSerialized] private GUIContent deleteGuiContent; [SerializeField] private string commitBody = ""; [SerializeField] private string commitMessage = ""; @@ -161,45 +160,30 @@ private void OnTreeGUI(Rect rect) private GenericMenu CreateContextMenu(ChangesTreeNode node) { var genericMenu = new GenericMenu(); - var canRevert = false; - var canDelete = false; + var canDiscard = false; if (!node.isFolder) { - canRevert = node.GitFileStatus == GitFileStatus.Added + canDiscard = node.GitFileStatus == GitFileStatus.Added || node.GitFileStatus == GitFileStatus.Modified || node.GitFileStatus == GitFileStatus.Deleted - || node.GitFileStatus == GitFileStatus.Renamed; - - canDelete = node.GitFileStatus == GitFileStatus.Untracked; + || node.GitFileStatus == GitFileStatus.Renamed + || node.GitFileStatus == GitFileStatus.Untracked; } - if (canRevert) + if (canDiscard) { if (revertGuiContent == null) { - revertGuiContent = new GUIContent("Revert"); + revertGuiContent = new GUIContent("Discard"); } genericMenu.AddItem(revertGuiContent, false, () => { - Repository.DiscardChanges(new List { node.Path }) + Repository.DiscardChanges(new List { node.GitStatusEntry }) .Start(); }); } - if (canDelete) - { - if (deleteGuiContent == null) - { - deleteGuiContent = new GUIContent("Delete"); - } - - genericMenu.AddItem(deleteGuiContent, false, () => { - Repository.DeleteFiles(new List { node.Path }) - .Start(); - }); - } - return genericMenu; } From bc63155dcebe8dadff05bd1861c1b712a664bf66 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 31 Jan 2018 18:16:13 -0500 Subject: [PATCH 0152/1008] Renaming the GuiContent variable --- .../Assets/Editor/GitHub.Unity/UI/ChangesView.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs index c631fe3c4..ba3c26118 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs @@ -23,7 +23,7 @@ class ChangesView : Subview [NonSerialized] private bool currentLocksHasUpdate; [NonSerialized] private bool isBusy; - [NonSerialized] private GUIContent revertGuiContent; + [NonSerialized] private GUIContent discardGuiContent; [SerializeField] private string commitBody = ""; [SerializeField] private string commitMessage = ""; @@ -173,12 +173,12 @@ private GenericMenu CreateContextMenu(ChangesTreeNode node) if (canDiscard) { - if (revertGuiContent == null) + if (discardGuiContent == null) { - revertGuiContent = new GUIContent("Discard"); + discardGuiContent = new GUIContent("Discard"); } - genericMenu.AddItem(revertGuiContent, false, () => { + genericMenu.AddItem(discardGuiContent, false, () => { Repository.DiscardChanges(new List { node.GitStatusEntry }) .Start(); }); From c08b7768edd3ce0d03e40621259a9bc31eec663d Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Feb 2018 09:50:12 -0500 Subject: [PATCH 0153/1008] Functionality to revert changes for a folder --- src/GitHub.Api/Git/IRepository.cs | 3 +- src/GitHub.Api/Git/Repository.cs | 4 +- src/GitHub.Api/Git/RepositoryManager.cs | 45 +++++++++---------- src/GitHub.Api/UI/TreeBase.cs | 27 +++++++++++ .../Editor/GitHub.Unity/UI/ChangesView.cs | 32 ++++++------- 5 files changed, 68 insertions(+), 43 deletions(-) diff --git a/src/GitHub.Api/Git/IRepository.cs b/src/GitHub.Api/Git/IRepository.cs index 83791f9f8..7acf918f0 100644 --- a/src/GitHub.Api/Git/IRepository.cs +++ b/src/GitHub.Api/Git/IRepository.cs @@ -18,8 +18,7 @@ public interface IRepository : IEquatable ITask Revert(string changeset); ITask RequestLock(string file); ITask ReleaseLock(string file, bool force); - ITask DiscardChanges(List files); - + ITask DiscardChanges(GitStatusEntry[] discardEntries); void CheckLogChangedEvent(CacheUpdateEvent gitLogCacheUpdateEvent); void CheckStatusChangedEvent(CacheUpdateEvent cacheUpdateEvent); void CheckStatusEntriesChangedEvent(CacheUpdateEvent cacheUpdateEvent); diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 68187ce70..16e509c05 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -112,9 +112,9 @@ public ITask ReleaseLock(string file, bool force) return repositoryManager.UnlockFile(file, force); } - public ITask DiscardChanges(List files) + public ITask DiscardChanges(GitStatusEntry[] gitStatusEntry) { - return repositoryManager.DiscardChanges(files); + return repositoryManager.DiscardChanges(gitStatusEntry); } public void CheckLogChangedEvent(CacheUpdateEvent cacheUpdateEvent) diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index e1bb81c2b..6bbddc9f0 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -17,6 +17,7 @@ public interface IRepositoryManager : IDisposable event Action> GitLogUpdated; event Action> LocalBranchesUpdated; event Action, Dictionary>> RemoteBranchesUpdated; + event Action GitAheadBehindStatusUpdated; void Initialize(); void Start(); @@ -35,7 +36,7 @@ public interface IRepositoryManager : IDisposable ITask CreateBranch(string branch, string baseBranch); ITask LockFile(string file); ITask UnlockFile(string file, bool force); - ITask DiscardChanges(List files); + ITask DiscardChanges(GitStatusEntry[] gitStatusEntries); void UpdateGitLog(); void UpdateGitStatus(); void UpdateGitAheadBehindStatus(); @@ -45,7 +46,6 @@ public interface IRepositoryManager : IDisposable IGitConfig Config { get; } IGitClient GitClient { get; } bool IsBusy { get; } - event Action GitAheadBehindStatusUpdated; } interface IRepositoryPathConfiguration @@ -292,33 +292,36 @@ public void UpdateGitStatus() task.Start(); } - public ITask DiscardChanges(List files) + public ITask DiscardChanges(GitStatusEntry[] gitStatusEntries) { - var itemsToDelete = files - .Where(entry => entry.status == GitFileStatus.Added - || entry.status == GitFileStatus.Untracked) - .Select(entry => entry.path) - .ToArray(); + Guard.ArgumentNotNullOrEmpty(gitStatusEntries, "gitStatusEntries"); + + var itemsToDelete = new List(); + var itemsToRevert = new List(); + + foreach (var gitStatusEntry in gitStatusEntries) + { + if (gitStatusEntry.status == GitFileStatus.Added || gitStatusEntry.status == GitFileStatus.Untracked) + { + itemsToDelete.Add(gitStatusEntry.path); + } + else + { + itemsToRevert.Add(gitStatusEntry.path); + } + } ActionTask deleteItemsTask = null; if (itemsToDelete.Any()) { deleteItemsTask = new ActionTask(CancellationToken.None, () => { - for (var index = 0; index < itemsToDelete.Length; index++) + foreach (var itemToDelete in itemsToDelete) { - var itemToDelete = itemsToDelete[index]; fileSystem.FileDelete(itemToDelete); } }); } - var itemsToRevert = files - .Where(entry => entry.status == GitFileStatus.Modified - || entry.status == GitFileStatus.Deleted - || entry.status == GitFileStatus.Renamed) - .Select(entry => entry.path) - .ToArray(); - ITask gitDiscardTask = null; if (itemsToRevert.Any()) { @@ -326,7 +329,7 @@ public ITask DiscardChanges(List files) } ITask task; - if(deleteItemsTask != null && gitDiscardTask != null) + if (deleteItemsTask != null && gitDiscardTask != null) { task = deleteItemsTask.Then(gitDiscardTask); } @@ -334,14 +337,10 @@ public ITask DiscardChanges(List files) { task = deleteItemsTask; } - else if (gitDiscardTask != null) + else //if (gitDiscardTask != null) { task = gitDiscardTask; } - else - { - throw new NotImplementedException(); - } return HookupHandlers(task, true, true); } diff --git a/src/GitHub.Api/UI/TreeBase.cs b/src/GitHub.Api/UI/TreeBase.cs index fecf2063f..0c46b1888 100644 --- a/src/GitHub.Api/UI/TreeBase.cs +++ b/src/GitHub.Api/UI/TreeBase.cs @@ -290,6 +290,33 @@ private void ToggleChildrenChecked(int idx, TNode node, bool isChecked) } } + public List GetLeafNodes(TNode parentNode) + { + var index = Nodes.IndexOf(parentNode); + return GetLeafNodes(parentNode, index); + } + + private List GetLeafNodes(TNode node, int idx) + { + var results = new List(); + for (var i = idx + 1; i < Nodes.Count && node.Level < Nodes[i].Level; i++) + { + var childNode = Nodes[i]; + if (childNode.IsFolder) + { + var leafNodes = GetLeafNodes(childNode, i); + results.AddRange(leafNodes); + } + else + { + results.Add(childNode); + } + } + + return results; + } + + private void ToggleParentFoldersChecked(int idx, TNode node, bool isChecked) { while (true) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs index ba3c26118..3b17ea5ad 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs @@ -160,29 +160,29 @@ private void OnTreeGUI(Rect rect) private GenericMenu CreateContextMenu(ChangesTreeNode node) { var genericMenu = new GenericMenu(); - var canDiscard = false; - if (!node.isFolder) + if (discardGuiContent == null) { - canDiscard = node.GitFileStatus == GitFileStatus.Added - || node.GitFileStatus == GitFileStatus.Modified - || node.GitFileStatus == GitFileStatus.Deleted - || node.GitFileStatus == GitFileStatus.Renamed - || node.GitFileStatus == GitFileStatus.Untracked; + discardGuiContent = new GUIContent("Discard"); } - if (canDiscard) - { - if (discardGuiContent == null) + genericMenu.AddItem(discardGuiContent, false, () => { + GitStatusEntry[] discardEntries; + if (node.isFolder) + { + discardEntries = treeChanges + .GetLeafNodes(node) + .Select(treeNode => treeNode.GitStatusEntry) + .ToArray(); + } + else { - discardGuiContent = new GUIContent("Discard"); + discardEntries = new [] { node.GitStatusEntry }; } - genericMenu.AddItem(discardGuiContent, false, () => { - Repository.DiscardChanges(new List { node.GitStatusEntry }) - .Start(); - }); - } + Repository.DiscardChanges(discardEntries) + .Start(); + }); return genericMenu; } From 3c1e8330bba1bb4010df54e8226407d8ea21b3b4 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 15 Feb 2018 16:29:11 +0100 Subject: [PATCH 0154/1008] Fix argument order, services should come before data. Also use cancellation tokens --- .../Application/ApplicationManagerBase.cs | 2 +- src/GitHub.Api/Git/RepositoryManager.cs | 15 ++++++++++----- .../IntegrationTests/BaseGitEnvironmentTest.cs | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 249f4e237..d4924da39 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -128,7 +128,7 @@ public void RestartRepository() { if (Environment.RepositoryPath != null) { - repositoryManager = Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, ProcessManager, Environment.RepositoryPath, Environment.FileSystem); + repositoryManager = Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, ProcessManager, Environment.FileSystem, Environment.RepositoryPath); repositoryManager.Initialize(); Environment.Repository.Initialize(repositoryManager); repositoryManager.Start(); diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index 6bbddc9f0..24acde4a8 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -100,6 +100,7 @@ class RepositoryManager : IRepositoryManager private readonly IProcessManager processManager; private readonly IRepositoryPathConfiguration repositoryPaths; private readonly IFileSystem fileSystem; + private readonly CancellationToken token; private readonly IRepositoryWatcher watcher; private bool isBusy; @@ -116,11 +117,13 @@ class RepositoryManager : IRepositoryManager public RepositoryManager(IGitConfig gitConfig, IRepositoryWatcher repositoryWatcher, IGitClient gitClient, IProcessManager processManager, - IRepositoryPathConfiguration repositoryPaths, - IFileSystem fileSystem) + IFileSystem fileSystem, + CancellationToken token, + IRepositoryPathConfiguration repositoryPaths) { this.repositoryPaths = repositoryPaths; this.fileSystem = fileSystem; + this.token = token; this.gitClient = gitClient; this.processManager = processManager; this.watcher = repositoryWatcher; @@ -129,7 +132,8 @@ public RepositoryManager(IGitConfig gitConfig, SetupWatcher(); } - public static RepositoryManager CreateInstance(IPlatform platform, ITaskManager taskManager, IGitClient gitClient, IProcessManager processManager, NPath repositoryRoot, IFileSystem fileSystem) + public static RepositoryManager CreateInstance(IPlatform platform, ITaskManager taskManager, IGitClient gitClient, + IProcessManager processManager, IFileSystem fileSystem, NPath repositoryRoot) { var repositoryPathConfiguration = new RepositoryPathConfiguration(repositoryRoot); string filePath = repositoryPathConfiguration.DotGitConfig; @@ -138,7 +142,8 @@ public static RepositoryManager CreateInstance(IPlatform platform, ITaskManager var repositoryWatcher = new RepositoryWatcher(platform, repositoryPathConfiguration, taskManager.Token); return new RepositoryManager(gitConfig, repositoryWatcher, - gitClient, processManager, repositoryPathConfiguration, fileSystem); + gitClient, processManager, fileSystem, + taskManager.Token, repositoryPathConfiguration); } public void Initialize() @@ -389,7 +394,7 @@ public void UpdateLocks() private ITask HookupHandlers(ITask task, bool isExclusive, bool filesystemChangesExpected) { - return new ActionTask(CancellationToken.None, () => { + return new ActionTask(token, () => { if (isExclusive) { Logger.Trace("Starting Operation - Setting Busy Flag"); diff --git a/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs b/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs index c840f236c..d19d2777c 100644 --- a/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs +++ b/src/tests/IntegrationTests/BaseGitEnvironmentTest.cs @@ -14,7 +14,7 @@ protected IEnvironment Initialize(NPath repoPath, NPath environmentPath = null, { InitializePlatform(repoPath, environmentPath, enableEnvironmentTrace); - var repositoryManager = GitHub.Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, ProcessManager, repoPath, Environment.FileSystem); + var repositoryManager = GitHub.Unity.RepositoryManager.CreateInstance(Platform, TaskManager, GitClient, ProcessManager, Environment.FileSystem, repoPath); onRepositoryManagerCreated?.Invoke(repositoryManager); RepositoryManager = repositoryManager; From a529043e1b6f274efde25b65c1cf19484f07da34 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 15 Feb 2018 19:55:59 +0100 Subject: [PATCH 0155/1008] Run all of discard on a thread --- src/GitHub.Api/Git/RepositoryManager.cs | 68 +++++++++++-------------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index 24acde4a8..119a62ea1 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -301,51 +301,41 @@ public ITask DiscardChanges(GitStatusEntry[] gitStatusEntries) { Guard.ArgumentNotNullOrEmpty(gitStatusEntries, "gitStatusEntries"); - var itemsToDelete = new List(); - var itemsToRevert = new List(); - - foreach (var gitStatusEntry in gitStatusEntries) - { - if (gitStatusEntry.status == GitFileStatus.Added || gitStatusEntry.status == GitFileStatus.Untracked) - { - itemsToDelete.Add(gitStatusEntry.path); - } - else + ActionTask task = null; + task = new ActionTask(token, (_, entries) => { - itemsToRevert.Add(gitStatusEntry.path); - } - } + var itemsToDelete = new List(); + var itemsToRevert = new List(); - ActionTask deleteItemsTask = null; - if (itemsToDelete.Any()) - { - deleteItemsTask = new ActionTask(CancellationToken.None, () => { - foreach (var itemToDelete in itemsToDelete) + foreach (var gitStatusEntry in gitStatusEntries) { - fileSystem.FileDelete(itemToDelete); + if (gitStatusEntry.status == GitFileStatus.Added || gitStatusEntry.status == GitFileStatus.Untracked) + { + itemsToDelete.Add(gitStatusEntry.path); + } + else + { + itemsToRevert.Add(gitStatusEntry.path); + } } - }); - } - ITask gitDiscardTask = null; - if (itemsToRevert.Any()) - { - gitDiscardTask = GitClient.Discard(itemsToRevert); - } + if (itemsToDelete.Any()) + { + foreach (var itemToDelete in itemsToDelete) + { + fileSystem.FileDelete(itemToDelete); + } + } + + ITask gitDiscardTask = null; + if (itemsToRevert.Any()) + { + gitDiscardTask = GitClient.Discard(itemsToRevert); + task.Then(gitDiscardTask); + } + } + , () => gitStatusEntries); - ITask task; - if (deleteItemsTask != null && gitDiscardTask != null) - { - task = deleteItemsTask.Then(gitDiscardTask); - } - else if (deleteItemsTask != null) - { - task = deleteItemsTask; - } - else //if (gitDiscardTask != null) - { - task = gitDiscardTask; - } return HookupHandlers(task, true, true); } From 6d3bae9b7b005e78679c15f07fc7a66d55351e3c Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 15 Feb 2018 19:56:55 +0100 Subject: [PATCH 0156/1008] Fix serialization of ChangesTreeNode --- .../GitHub.Unity/UI/ChangesTreeControl.cs | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs index 798244dc4..45e4c33c3 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs @@ -13,48 +13,45 @@ public class ChangesTreeNodeDictionary : SerializableDictionary { + [NonSerialized] public Texture2D FolderIcon; + [SerializeField] public ChangesTreeNodeDictionary assets = new ChangesTreeNodeDictionary(); [SerializeField] public ChangesTreeNodeDictionary folders = new ChangesTreeNodeDictionary(); [SerializeField] public ChangesTreeNodeDictionary checkedFileNodes = new ChangesTreeNodeDictionary(); - - [NonSerialized] public Texture2D FolderIcon; [SerializeField] public string title = string.Empty; [SerializeField] public string pathSeparator = "/"; [SerializeField] public bool displayRootNode = true; [SerializeField] public bool isSelectable = true; [SerializeField] public bool isCheckable = false; [SerializeField] public bool isUsingGlobalSelection = false; - [SerializeField] private List nodes = new List(); - [SerializeField] private ChangesTreeNode selectedNode = null; + [NonSerialized] private bool viewHasFocus; [NonSerialized] private Object lastActivatedObject; + [SerializeField] private List nodes = new List(); + [SerializeField] private ChangesTreeNode selectedNode = null; + public override string Title { get { return title; } From 0f5db5f8c010dc26e52574e52e827d8454ce6c4c Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Sat, 17 Feb 2018 12:50:15 +0100 Subject: [PATCH 0157/1008] Update the Unity version requirements --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 71571e1c0..36429c3ad 100644 --- a/README.md +++ b/README.md @@ -47,8 +47,8 @@ The GitHub for Unity extension brings [Git](https://git-scm.com/) and GitHub int ### Requirements -- Unity 5.4-2017.1 - - We've only tested the extension so far on Unity 5.4 to 2017.1. There's currently an blocker issue opened for 5.3 support, so we know it doesn't run there. There are some issues for 2017.2, so it may or may not run well on that version. Personal edition is fine. +- Unity 5.4 or higher + - There's currently an blocker issue opened for 5.3 support, so we know it doesn't run there. Personal edition is fine. - Git and Git LFS 2.x #### Git on macOS From 2270f0e4f65103c69842f3b98ad8cee5d25a4a3c Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 19 Feb 2018 17:29:46 +0100 Subject: [PATCH 0158/1008] Loading spinner and progress reporting --- .../Application/ApplicationManagerBase.cs | 10 +- .../Application/IApplicationManager.cs | 3 +- src/GitHub.Api/Installer/GitInstaller.cs | 60 ++++- src/GitHub.Api/Installer/IZipHelper.cs | 2 +- src/GitHub.Api/Installer/UnzipTask.cs | 17 +- src/GitHub.Api/Installer/ZipHelper.cs | 104 +-------- .../Editor/GitHub.Unity/ApplicationManager.cs | 1 + .../Assets/Editor/GitHub.Unity/EntryPoint.cs | 4 +- .../Editor/GitHub.Unity/GitHub.Unity.csproj | 15 ++ .../GitHub.Unity/IconsAndLogos/code.png | 3 + .../GitHub.Unity/IconsAndLogos/code@2x.png | 3 + .../GitHub.Unity/IconsAndLogos/merge.png | 3 + .../GitHub.Unity/IconsAndLogos/merge@2x.png | 3 + .../GitHub.Unity/IconsAndLogos/rocket.png | 3 + .../GitHub.Unity/IconsAndLogos/rocket@2x.png | 3 + .../IconsAndLogos/spinner-inside.png | 3 + .../IconsAndLogos/spinner-inside@2x.png | 3 + .../IconsAndLogos/spinner-outside.png | 3 + .../IconsAndLogos/spinner-outside@2x.png | 3 + .../Assets/Editor/GitHub.Unity/Misc/Styles.cs | 138 +++++++++++- .../Editor/GitHub.Unity/Misc/Utility.cs | 16 ++ .../Editor/GitHub.Unity/UI/BaseWindow.cs | 2 +- .../Editor/GitHub.Unity/UI/SettingsView.cs | 2 +- .../Assets/Editor/GitHub.Unity/UI/Spinner.cs | 207 ++++++++++++++++++ .../Assets/Editor/GitHub.Unity/UI/Window.cs | 135 +++++++----- .../BaseGitEnvironmentTest.cs | 2 +- src/tests/IntegrationTests/UnzipTaskTests.cs | 17 +- 27 files changed, 586 insertions(+), 179 deletions(-) create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/code.png create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/code@2x.png create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/merge.png create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/merge@2x.png create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/rocket.png create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/rocket@2x.png create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/spinner-inside.png create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/spinner-inside@2x.png create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/spinner-outside.png create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/spinner-outside@2x.png create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Spinner.cs diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 61894c369..a00d9790a 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -12,6 +12,8 @@ abstract class ApplicationManagerBase : IApplicationManager protected static ILogging Logger { get; } = LogHelper.GetLogger(); private RepositoryManager repositoryManager; + protected bool isBusy; + public event Action OnProgress; public ApplicationManagerBase(SynchronizationContext synchronizationContext) { @@ -57,9 +59,11 @@ public void Run(bool firstRun) { Logger.Trace("No git path found in settings"); + isBusy = true; var initEnvironmentTask = new ActionTask(CancellationToken, (b, path) => InitializeEnvironment(path)) { Affinity = TaskAffinity.UI }; var findExecTask = new FindExecTask("git", CancellationToken) - .FinallyInUI((b, ex, path) => { + .FinallyInUI((b, ex, path) => + { if (b && path != null) { Logger.Trace("FindExecTask Success: {0}", path); @@ -70,6 +74,7 @@ public void Run(bool firstRun) Logger.Warning("FindExecTask Failure"); Logger.Error("Git not found"); } + isBusy = false; }); var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); @@ -190,7 +195,7 @@ private void InitializeEnvironment(NPath gitExecutablePath) } else { - Logger.Warning("No Windows CredentialHeloper found: Setting to wincred"); + Logger.Warning("No Windows CredentialHelper found: Setting to wincred"); GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global) .Then(afterGitSetup) @@ -234,6 +239,7 @@ public void Dispose() public ISettings SystemSettings { get; protected set; } public ISettings UserSettings { get; protected set; } public IUsageTracker UsageTracker { get; protected set; } + public bool IsBusy { get { return isBusy || RepositoryManager.IsBusy; } } protected TaskScheduler UIScheduler { get; private set; } protected SynchronizationContext SynchronizationContext { get; private set; } protected IRepositoryManager RepositoryManager { get { return repositoryManager; } } diff --git a/src/GitHub.Api/Application/IApplicationManager.cs b/src/GitHub.Api/Application/IApplicationManager.cs index fd59878a8..4642101ed 100644 --- a/src/GitHub.Api/Application/IApplicationManager.cs +++ b/src/GitHub.Api/Application/IApplicationManager.cs @@ -17,9 +17,10 @@ public interface IApplicationManager : IDisposable ITaskManager TaskManager { get; } IGitClient GitClient { get; } IUsageTracker UsageTracker { get; } - + bool IsBusy { get; } void Run(bool firstRun); void RestartRepository(); ITask InitializeRepository(); + event Action OnProgress; } } \ No newline at end of file diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 8fb339f56..a1cf21a92 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -77,6 +77,8 @@ class GitInstaller private readonly IZipHelper sharpZipLibHelper; private NPath gitArchiveFilePath; private NPath gitLfsArchivePath; + private Progress progress = new Progress(); + public event Action OnProgress; public GitInstaller(IEnvironment environment, CancellationToken cancellationToken, GitInstallDetails installDetails) @@ -115,6 +117,9 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) if (IsGitExtracted()) { Logger.Trace("SetupGitIfNeeded: Skipped"); + progress.Total = 100; + progress.Value = 100; + OnProgress?.Invoke(progress); onSuccess.PreviousResult = installDetails.GitExecutablePath; onSuccess.Start(); } @@ -127,6 +132,7 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) private void ExtractPortableGit(ActionTask onSuccess, ITask onFailure) { + Logger.Trace("ExtractPortableGit"); ITask downloadFilesTask = null; if ((gitArchiveFilePath == null) || (gitLfsArchivePath == null)) { @@ -138,7 +144,19 @@ private void ExtractPortableGit(ActionTask onSuccess, ITask onFailure) var gitLfsExtractPath = tempZipExtractPath.Combine("git-lfs").CreateDirectory(); var resultTask = new UnzipTask(cancellationToken, gitArchiveFilePath, gitExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitExtractedMD5) + .Progress(p => + { + progress.Task = p.Task; + var pt = p.Value / p.Total; + progress.Value = 40 + 20 * pt; + }) .Then(new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails .GitLfsExtractedMD5)) + .Progress(p => + { + progress.Task = p.Task; + var pt = p.Value / p.Total; + progress.Value = 60 + 20 * pt; + }) .Then(s => MoveGitAndLfs(gitExtractPath, gitLfsExtractPath, tempZipExtractPath)); resultTask.Then(onFailure, TaskRunOptions.OnFailure); @@ -154,6 +172,9 @@ private void ExtractPortableGit(ActionTask onSuccess, ITask onFailure) private NPath MoveGitAndLfs(NPath gitExtractPath, NPath gitLfsExtractPath, NPath tempZipExtractPath) { + progress.Value = 80; + OnProgress?.Invoke(progress); + var targetGitLfsExecPath = installDetails.GetGitLfsExecutablePath(gitExtractPath); var extractGitLfsExePath = gitLfsExtractPath.Combine(installDetails.GitLfsExecutable); @@ -163,6 +184,9 @@ private NPath MoveGitAndLfs(NPath gitExtractPath, NPath gitLfsExtractPath, NPath Logger.Trace($"Moving tempDirectory:'{gitExtractPath}' to extractTarget:'{installDetails.GitInstallationPath}'"); + progress.Value = 90; + OnProgress?.Invoke(progress); + installDetails.GitInstallationPath.EnsureParentDirectoryExists(); gitExtractPath.Move(installDetails.GitInstallationPath); @@ -182,22 +206,46 @@ private ITask CreateDownloadTask() gitLfsArchivePath = tempZipPath.Combine("git-lfs.zip"); var downloadGitMd5Task = new DownloadTextTask(TaskManager.Instance.Token, environment.FileSystem, - installDetails.GitZipMd5Url, tempZipPath); + installDetails.GitZipMd5Url, tempZipPath) + .Progress(p => + { + progress.Task = p.Task; + var pt = p.Value / p.Total; + progress.Value = 10 * pt; + }); var downloadGitTask = new DownloadTask(TaskManager.Instance.Token, environment.FileSystem, - installDetails.GitZipUrl, tempZipPath); + installDetails.GitZipUrl, tempZipPath) + .Progress(p => + { + progress.Task = p.Task; + var pt = p.Value / p.Total; + progress.Value = 10 + 10 * pt; + }); var downloadGitLfsMd5Task = new DownloadTextTask(TaskManager.Instance.Token, environment.FileSystem, - installDetails.GitLfsZipMd5Url, tempZipPath); + installDetails.GitLfsZipMd5Url, tempZipPath) + .Progress(p => + { + progress.Task = p.Task; + var pt = p.Value / p.Total; + progress.Value = 20 + 10 * pt; + }); var downloadGitLfsTask = new DownloadTask(TaskManager.Instance.Token, environment.FileSystem, - installDetails.GitLfsZipUrl, tempZipPath); + installDetails.GitLfsZipUrl, tempZipPath) + .Progress(p => + { + progress.Task = p.Task; + var pt = p.Value / p.Total; + progress.Value = 30 + 10 * pt; + }); return - downloadGitMd5Task.Then((b, s) => { downloadGitTask.ValidationHash = s; }) + downloadGitMd5Task.Then((b, s) => { ((DownloadTask)downloadGitTask).ValidationHash = s; }) .Then(downloadGitTask) .Then(downloadGitLfsMd5Task) - .Then((b, s) => { downloadGitLfsTask.ValidationHash = s; }) + .Then((b, s) => { ((DownloadTask)downloadGitLfsTask).ValidationHash = s; }) .Then(downloadGitLfsTask); } diff --git a/src/GitHub.Api/Installer/IZipHelper.cs b/src/GitHub.Api/Installer/IZipHelper.cs index 7f6c1d84e..a536dcadf 100644 --- a/src/GitHub.Api/Installer/IZipHelper.cs +++ b/src/GitHub.Api/Installer/IZipHelper.cs @@ -6,6 +6,6 @@ namespace GitHub.Unity interface IZipHelper { void Extract(string archive, string outFolder, CancellationToken cancellationToken, - IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null); + Func onProgress = null); } } diff --git a/src/GitHub.Api/Installer/UnzipTask.cs b/src/GitHub.Api/Installer/UnzipTask.cs index f12902eef..b8b6ae3db 100644 --- a/src/GitHub.Api/Installer/UnzipTask.cs +++ b/src/GitHub.Api/Installer/UnzipTask.cs @@ -11,16 +11,14 @@ class UnzipTask: TaskBase private readonly IZipHelper zipHelper; private readonly IFileSystem fileSystem; private readonly string expectedMD5; - private readonly IProgress zipFileProgress; - private readonly IProgress estimatedDurationProgress; - public UnzipTask(CancellationToken token, string archiveFilePath, NPath extractedPath, IFileSystem fileSystem, string expectedMD5 = null, IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) : - this(token, archiveFilePath, extractedPath, ZipHelper.Instance, fileSystem, expectedMD5, zipFileProgress, estimatedDurationProgress) + public UnzipTask(CancellationToken token, string archiveFilePath, NPath extractedPath, IFileSystem fileSystem, string expectedMD5 = null) : + this(token, archiveFilePath, extractedPath, ZipHelper.Instance, fileSystem, expectedMD5) { } - public UnzipTask(CancellationToken token, string archiveFilePath, NPath extractedPath, IZipHelper zipHelper, IFileSystem fileSystem, string expectedMD5 = null, IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) + public UnzipTask(CancellationToken token, string archiveFilePath, NPath extractedPath, IZipHelper zipHelper, IFileSystem fileSystem, string expectedMD5 = null) : base(token) { this.archiveFilePath = archiveFilePath; @@ -28,8 +26,6 @@ public UnzipTask(CancellationToken token, string archiveFilePath, NPath extracte this.zipHelper = zipHelper; this.fileSystem = fileSystem; this.expectedMD5 = expectedMD5; - this.zipFileProgress = zipFileProgress; - this.estimatedDurationProgress = estimatedDurationProgress; } protected override void Run(bool success) @@ -40,7 +36,12 @@ protected override void Run(bool success) try { - zipHelper.Extract(archiveFilePath, extractedPath, Token, zipFileProgress, estimatedDurationProgress); + zipHelper.Extract(archiveFilePath, extractedPath, Token, + (value, total) => + { + UpdateProgress(value, total); + return !Token.IsCancellationRequested; + }); } catch (Exception ex) { diff --git a/src/GitHub.Api/Installer/ZipHelper.cs b/src/GitHub.Api/Installer/ZipHelper.cs index 34701b803..554ec7d17 100644 --- a/src/GitHub.Api/Installer/ZipHelper.cs +++ b/src/GitHub.Api/Installer/ZipHelper.cs @@ -23,87 +23,17 @@ public static IZipHelper Instance } } - public static bool Copy(Stream source, Stream destination, int chunkSize, long totalSize, - Func progress, int progressUpdateRate) - { - var buffer = new byte[chunkSize]; - var bytesRead = 0; - long totalRead = 0; - var averageSpeed = -1f; - var lastSpeed = 0f; - var smoothing = 0.005f; - long readLastSecond = 0; - long timeToFinish = 0; - Stopwatch watch = null; - var success = true; - - var trackProgress = totalSize > 0 && progress != null; - if (trackProgress) - { - watch = new Stopwatch(); - } - - do - { - if (trackProgress) - { - watch.Start(); - } - - bytesRead = source.Read(buffer, 0, chunkSize); - - if (trackProgress) - { - watch.Stop(); - } - - totalRead += bytesRead; - - if (bytesRead > 0) - { - destination.Write(buffer, 0, bytesRead); - if (trackProgress) - { - readLastSecond += bytesRead; - if (watch.ElapsedMilliseconds >= progressUpdateRate || totalRead == totalSize) - { - watch.Reset(); - lastSpeed = readLastSecond; - readLastSecond = 0; - averageSpeed = averageSpeed < 0f - ? lastSpeed - : smoothing * lastSpeed + (1f - smoothing) * averageSpeed; - timeToFinish = Math.Max(1L, - (long)((totalSize - totalRead) / (averageSpeed / progressUpdateRate))); - - if (!progress(totalRead, timeToFinish)) - { - break; - } - } - } - } - } while (bytesRead > 0); - - if (totalRead > 0) - { - destination.Flush(); - } - - return success; - } - public void Extract(string archive, string outFolder, CancellationToken cancellationToken, - IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) + Func onProgress = null) { - ExtractZipFile(archive, outFolder, cancellationToken, zipFileProgress, estimatedDurationProgress); + ExtractZipFile(archive, outFolder, cancellationToken, onProgress); } public static void ExtractZipFile(string archive, string outFolder, CancellationToken cancellationToken, - IProgress zipFileProgress = null, IProgress estimatedDurationProgress = null) + Func onProgress) { + const int chunkSize = 4096; // 4K is optimum ZipFile zf = null; - var estimatedDuration = 1L; var startTime = DateTime.Now; var processed = 0; var totalBytes = 0L; @@ -112,9 +42,11 @@ public static void ExtractZipFile(string archive, string outFolder, Cancellation { var fs = File.OpenRead(archive); zf = new ZipFile(fs); + var totalSize = fs.Length; foreach (ZipEntry zipEntry in zf) { + cancellationToken.ThrowIfCancellationRequested(); if (zipEntry.IsDirectory) { continue; // Ignore directories @@ -152,28 +84,16 @@ public static void ExtractZipFile(string archive, string outFolder, Cancellation var targetFile = new FileInfo(fullZipToPath); using (var streamWriter = targetFile.OpenWrite()) { - const int chunkSize = 4096; // 4K is optimum - Copy(zipStream, streamWriter, chunkSize, targetFile.Length, (totalRead, timeToFinish) => - { - estimatedDuration = timeToFinish; - - estimatedDurationProgress.Report(estimatedDuration); - zipFileProgress?.Report((float)(totalBytes + totalRead) / targetFile.Length); - return true; - }, 100); - cancellationToken.ThrowIfCancellationRequested(); + if (!Utils.Copy(zipStream, streamWriter, targetFile.Length, chunkSize, + progress: (totalRead, timeToFinish) => { + totalBytes += totalRead; + return onProgress(totalBytes, totalSize); + })) + return; } targetFile.LastWriteTime = zipEntry.DateTime; processed++; - totalBytes += zipEntry.Size; - - var elapsedMillisecondsPerFile = (DateTime.Now - startTime).TotalMilliseconds / processed; - estimatedDuration = Math.Max(1L, (long)((fs.Length - totalBytes) * elapsedMillisecondsPerFile)); - - estimatedDurationProgress?.Report(estimatedDuration); - zipFileProgress?.Report((float)processed / zf.Count); - cancellationToken.ThrowIfCancellationRequested(); } } finally diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs index c5fcfd00c..fd09a6781 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs @@ -31,6 +31,7 @@ protected override void InitializeUI() Logger.Trace("Restarted {0}", Environment.Repository); EnvironmentCache.Instance.Flush(); + isBusy = false; ProjectWindowInterface.Initialize(Environment.Repository); var window = Window.GetWindow(); if (window != null) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs index 3b25a5277..7cfa0d5d3 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs @@ -62,7 +62,9 @@ private static void Initialize() Debug.LogFormat("Initialized GitHub for Unity version {0}{1}Log file: {2}", ApplicationInfo.Version, Environment.NewLine, logPath); } - LogHelper.LogAdapter = new FileLogAdapter(logPath); + LogHelper.LogAdapter = new MultipleLogAdapter(new FileLogAdapter(logPath) + , new UnityLogAdapter() + ); LogHelper.Info("Initializing GitHub for Unity version " + ApplicationInfo.Version); ApplicationManager.Run(ApplicationCache.Instance.FirstRun); diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj index 1bc293176..e4bb48940 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj @@ -108,6 +108,7 @@ + @@ -217,6 +218,20 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/OctoRun/Program.cs b/src/OctoRun/Program.cs new file mode 100644 index 000000000..dd6cd4a32 --- /dev/null +++ b/src/OctoRun/Program.cs @@ -0,0 +1,113 @@ +using GitHub.Unity; +using Mono.Options; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading.Tasks; +using static OctoRun.LoginManager; + +namespace OctoRun +{ + class LoginCommand + { + public Command[] Commands { get; private set; } + private string host; + private bool in2fa; + + public static LoginCommand Initialize() + { + var instance = new LoginCommand(); + instance.Commands = new Command[] + { + new Command("login", "login") + { + Options = new OptionSet { + { "h|host=", host => instance.host = host }, + { "2fa", v => instance.in2fa = v != null } + }, + Run = args => instance.Run(args) + } + }; + return instance; + } + + public void Run(IEnumerable args) + { + DoLogin(); + } + + private void DoLogin() + { + var login = Console.ReadLine(); + var token = Console.ReadLine(); + string twofa = null; + if (in2fa) + twofa = Console.ReadLine(); + var credStore = new CredentialStore { Login = login, Token = token, Code = twofa }; + var hostAddress = HostAddress.Create(host); + var client = new ApiClient(credStore, hostAddress); + + LoginResult result = null; + if (!in2fa) + { + result = client.Login(); + if (result.NeedTwoFA) + { + Console.WriteLine("2fa"); + Console.WriteLine(credStore.Token); + } + else if (result.Success) + { + Console.WriteLine(credStore.Token); + } + else + { + Console.WriteLine("failed"); + Console.WriteLine(result.Message); + } + } + else + { + result = client.ContinueLogin(); + if (result.NeedTwoFA) + { + Console.WriteLine("2fa"); + Console.WriteLine(credStore.Token); + } + else if (result.Success) + { + Console.WriteLine(credStore.Token); + } + else + { + Console.WriteLine("failed"); + Console.WriteLine(result.Message); + } + } + + } + } + + class Program + { + static void Main(string[] args) + { + Logging.LogAdapter = new ConsoleLogAdapter(); + + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + + var opts = new OptionSet(); + var commands = new CommandSet(""); + foreach (var cmd in LoginCommand.Initialize().Commands) + commands.Add(cmd); + + opts.Parse(args); + commands.Run(args); + } + + private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + Debugger.Break(); + } + } +} diff --git a/src/OctoRun/Properties/AssemblyInfo.cs b/src/OctoRun/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..7b4846420 --- /dev/null +++ b/src/OctoRun/Properties/AssemblyInfo.cs @@ -0,0 +1,12 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OctoRun")] +[assembly: AssemblyDescription("")] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("127f84fe-db89-4543-9a83-74db4e751061")] diff --git a/src/OctoRun/StringEquivalent.cs b/src/OctoRun/StringEquivalent.cs new file mode 100644 index 000000000..88756fe82 --- /dev/null +++ b/src/OctoRun/StringEquivalent.cs @@ -0,0 +1,109 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +namespace OctoRun +{ + [Serializable] + public abstract class StringEquivalent : ISerializable, IXmlSerializable where T : StringEquivalent + { + protected string Value; + + protected StringEquivalent(string value) + { + Value = value; + } + + protected StringEquivalent() + { + } + + public abstract T Combine(string addition); + + [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "Add doesn't make sense in the case of a string equivalent")] + public static T operator +(StringEquivalent a, string b) + { + return a.Combine(b); + } + + public static bool operator ==(StringEquivalent a, StringEquivalent b) + { + // If both are null, or both are same instance, return true. + if (ReferenceEquals(a, b)) + { + return true; + } + + // If one is null, but not both, return false. + if (((object)a == null) || ((object)b == null)) + { + return false; + } + + // Return true if the fields match: + return a.Value.Equals(b.Value, StringComparison.OrdinalIgnoreCase); + } + + public static bool operator !=(StringEquivalent a, StringEquivalent b) + { + return !(a == b); + } + + public override bool Equals(Object obj) + { + return obj != null && Equals(obj as T) || Equals(obj as string); + } + + public virtual bool Equals(T stringEquivalent) + { + return this == stringEquivalent; + } + + public override int GetHashCode() + { + return (Value ?? "").GetHashCode(); + } + + public virtual bool Equals(string other) + { + return other != null && Value == other; + } + + public override string ToString() + { + return Value; + } + + protected StringEquivalent(SerializationInfo info) : this(info.GetValue("Value", typeof(string)) as string) + { + } + + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("Value", Value); + } + + public XmlSchema GetSchema() + { + return null; + } + + public void ReadXml(XmlReader reader) + { + Value = reader.ReadString(); + } + + public void WriteXml(XmlWriter writer) + { + writer.WriteString(Value); + } + + public int Length + { + get { return Value != null ? Value.Length : 0; } + } + } +} diff --git a/src/OctoRun/StringExtensions.cs b/src/OctoRun/StringExtensions.cs new file mode 100644 index 000000000..ce966542e --- /dev/null +++ b/src/OctoRun/StringExtensions.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; + +namespace OctoRun +{ + static class StringExtensions + { + public static bool Contains(this string s, string expectedSubstring, StringComparison comparison) + { + return s.IndexOf(expectedSubstring, comparison) > -1; + } + + public static bool ContainsAny(this string s, IEnumerable characters) + { + return s.IndexOfAny(characters.ToArray()) > -1; + } + + public static string ToNullIfEmpty(this string s) + { + return String.IsNullOrEmpty(s) ? null : s; + } + + public static bool StartsWith(this string s, char c) + { + if (String.IsNullOrEmpty(s)) return false; + return s.First() == c; + } + + public static string RightAfter(this string s, string search) + { + if (s == null) return null; + int lastIndex = s.IndexOf(search, StringComparison.OrdinalIgnoreCase); + if (lastIndex < 0) + return null; + + return s.Substring(lastIndex + search.Length); + } + + public static string RightAfterLast(this string s, string search) + { + if (s == null) return null; + int lastIndex = s.LastIndexOf(search, StringComparison.OrdinalIgnoreCase); + if (lastIndex < 0) + return null; + + return s.Substring(lastIndex + search.Length); + } + + public static string LeftBeforeLast(this string s, string search) + { + if (s == null) return null; + int lastIndex = s.LastIndexOf(search, StringComparison.OrdinalIgnoreCase); + if (lastIndex < 0) + return null; + + return s.Substring(0, lastIndex); + } + + public static string TrimEnd(this string s, string suffix) + { + if (s == null) return null; + if (!s.EndsWith(suffix, StringComparison.OrdinalIgnoreCase)) + return s; + + return s.Substring(0, s.Length - suffix.Length); + } + + /// + /// Pretty much the same things as `String.Join` but used when appending to an already delimited string. If the values passed + /// in are empty, it does not prepend the delimeter. Otherwise, it prepends with the delimiter. + /// + /// The separator character + /// The set values to join + public static string JoinForAppending(string separator, IEnumerable values) + { + return values.Any() + ? separator + String.Join(separator, values.ToArray()) + : string.Empty; + } + + public static string RemoveSurroundingQuotes(this string s) + { + Guard.ArgumentNotNull(s, "string"); + + if (s.Length < 2) + return s; + + var quoteCharacters = new[] { '"', '\'' }; + char firstCharacter = s[0]; + if (!quoteCharacters.Contains(firstCharacter)) + return s; + + if (firstCharacter != s[s.Length - 1]) + return s; + + return s.Substring(1, s.Length - 2); + } + + public static string RightAfter(this string s, char search) + { + if (s == null) return null; + int lastIndex = s.IndexOf(search); + if (lastIndex < 0) + return null; + + return s.Substring(lastIndex + 1); + } + + public static string RightAfterLast(this string s, char search) + { + if (s == null) return null; + int lastIndex = s.LastIndexOf(search); + if (lastIndex < 0) + return null; + + return s.Substring(lastIndex + 1); + } + + public static string LeftBeforeLast(this string s, char search) + { + if (s == null) return null; + int lastIndex = s.LastIndexOf(search); + if (lastIndex < 0) + return null; + + return s.Substring(0, lastIndex); + } + + public static StringResult? NextChunk(this string s, int start, char search) + { + if (s == null) return null; + int index = s.IndexOf(search, start); + if (index < 0) + return null; + + return new StringResult { Chunk = s.Substring(start, index - start), Start = start, End = index }; + } + + public static StringResult? NextChunk(this string s, int start, string search) + { + if (s == null) return null; + int index = s.IndexOf(search, start); + if (index < 0) + return null; + + return new StringResult { Chunk = s.Substring(start, index - start), Start = start, End = index }; + } + } + + public struct StringResult + { + public string Chunk; + public int Start; + public int End; + } +} diff --git a/src/OctoRun/UriExtensions.cs b/src/OctoRun/UriExtensions.cs new file mode 100644 index 000000000..c0e6893bf --- /dev/null +++ b/src/OctoRun/UriExtensions.cs @@ -0,0 +1,38 @@ +using System; + +namespace OctoRun +{ + static class UriExtensions + { + /// + /// Appends a relative path to the URL. + /// + /// + /// The Uri constructor for combining relative URLs have a different behavior with URLs that end with / + /// than those that don't. + /// + public static Uri Append(this Uri uri, string relativePath) + { + if (!uri.AbsolutePath.EndsWith("/", StringComparison.Ordinal)) + { + uri = new Uri(uri + "/"); + } + return new Uri(uri, new Uri(relativePath, UriKind.Relative)); + } + + public static bool IsHypertextTransferProtocol(this Uri uri) + { + return uri.Scheme == "http" || uri.Scheme == "https"; + } + + public static bool IsSameHost(this Uri uri, Uri compareUri) + { + return uri.Host.Equals(compareUri.Host, StringComparison.OrdinalIgnoreCase); + } + + public static UriString ToUriString(this Uri uri) + { + return uri == null ? null : new UriString(uri.ToString()); + } + } +} diff --git a/src/OctoRun/UriString.cs b/src/OctoRun/UriString.cs new file mode 100644 index 000000000..da91f50fa --- /dev/null +++ b/src/OctoRun/UriString.cs @@ -0,0 +1,285 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Runtime.Serialization; +using System.Text.RegularExpressions; + +namespace OctoRun +{ + /// + /// This class represents a URI given to us as a string and is implicitly + /// convertible to and from string. + /// + /// + /// This typically represents a URI from an external source such as user input, a + /// Git Repo Remote, or an API URL. We try to preserve the original form and let + /// downstream clients validate the URL. This class doesn't validate the URL. It just + /// performs a best-effort to parse the URI into bits important to us. For example, + /// we need to know the HOST so we can compare against GitHub.com, GH:E instances, etc. + /// + [SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly", Justification = "GetObjectData is implemented in the base class")] + [Serializable] + public class UriString : StringEquivalent, IEquatable + { + static readonly Regex sshRegex = new Regex(@"^.+@(?(\[.*?\]|[a-z0-9-.]+?))(:(?.*?))?(/(?.*)(\.git)?)?$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + readonly Uri url; + + public UriString(string uriString) : base(NormalizePath(uriString)) + { + if (uriString == null || uriString.Length == 0) return; + if (Uri.TryCreate(uriString, UriKind.Absolute, out url)) + { + if (!url.IsFile) + SetUri(url); + else + SetFilePath(url); + } + else if (!ParseScpSyntax(uriString)) + { + SetFilePath(uriString); + } + + if (RepositoryName != null) + { + NameWithOwner = Owner != null + ? string.Format(CultureInfo.InvariantCulture, "{0}/{1}", Owner, RepositoryName) + : RepositoryName; + } + } + + public static UriString ToUriString(Uri uri) + { + return uri == null ? null : new UriString(uri.ToString()); + } + + public static UriString TryParse(string uri) + { + if (uri == null || uri.Length == 0) return null; + return new UriString(uri); + } + + public Uri ToUri() + { + if (url == null) + throw new InvalidOperationException("This Uri String is not a valid Uri"); + return url; + } + + void SetUri(Uri uri) + { + Host = uri.Host; + if (uri.Segments.Any()) + { + RepositoryName = GetRepositoryName(uri.Segments.Last()); + } + + if (uri.Segments.Length > 2) + { + Owner = (uri.Segments[uri.Segments.Length - 2] ?? "").TrimEnd('/').ToNullIfEmpty(); + } + + IsHypertextTransferProtocol = uri.IsHypertextTransferProtocol(); + } + + void SetFilePath(Uri uri) + { + Host = ""; + Owner = ""; + RepositoryName = GetRepositoryName(uri.Segments.Last()); + IsFileUri = true; + } + + void SetFilePath(string path) + { + Host = ""; + Owner = ""; + RepositoryName = GetRepositoryName(path.Replace("/", @"\").RightAfterLast(@"\")); + IsFileUri = true; + } + + // For xml serialization + protected UriString() + { + } + + bool ParseScpSyntax(string scpString) + { + var match = sshRegex.Match(scpString); + if (match.Success) + { + Host = match.Groups["host"].Value.ToNullIfEmpty(); + Owner = match.Groups["owner"].Value.ToNullIfEmpty(); + RepositoryName = GetRepositoryName(match.Groups["repo"].Value); + IsScpUri = true; + return true; + } + return false; + } + + public string Host { get; private set; } + + public string Owner { get; private set; } + + public string RepositoryName { get; private set; } + + public string NameWithOwner { get; private set; } + + public bool IsFileUri { get; private set; } + + public bool IsScpUri { get; private set; } + + public bool IsValidUri => url != null; + public string Protocol => url?.Scheme; + + /// + /// Attempts a best-effort to convert the remote origin to a GitHub Repository URL. + /// + /// A converted uri, or the existing one if we can't convert it (which might be null) + public Uri ToRepositoryUri() + { + // we only want to process urls that represent network resources + if (!IsScpUri && (!IsValidUri || IsFileUri)) return url; + + var scheme = url != null && IsHypertextTransferProtocol + ? url.Scheme + : Uri.UriSchemeHttps; + + var port = url?.Port == 80 + ? -1 + : (url?.Port ?? -1); + return new UriBuilder + { + Scheme = scheme, + Host = Host, + Path = NameWithOwner, + Port = port + }.Uri; + } + + /// + /// Attempts a best-effort to convert the remote origin to a GitHub Repository URL. + /// + /// A converted uri, or the existing one if we can't convert it (which might be null) + public UriString ToRepositoryUrl() + { + // we only want to process urls that represent network resources + if (!IsScpUri && (!IsValidUri || IsFileUri)) return this; + + var scheme = url != null && IsHypertextTransferProtocol + ? url.Scheme + : Uri.UriSchemeHttps; + + var port = url?.Port == 80 + ? -1 + : (url?.Port ?? -1); + return new UriString(new UriBuilder + { + Scheme = scheme, + Host = Host, + Path = NameWithOwner, + Port = port + }.Uri.ToString()); + } + + /// + /// True if the URL is HTTP or HTTPS + /// + public bool IsHypertextTransferProtocol { get; private set; } + + [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates")] + public static implicit operator UriString(string value) + { + if (value == null) return null; + + return new UriString(value); + } + + [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates")] + public static implicit operator string(UriString uriString) + { + return uriString?.Value; + } + + [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "No.")] + public override UriString Combine(string addition) + { + if (url != null) + { + var urlBuilder = new UriBuilder(url); + if (!String.IsNullOrEmpty(urlBuilder.Query)) + { + var query = urlBuilder.Query; + if (query.StartsWith("?", StringComparison.Ordinal)) + { + query = query.Substring(1); + } + + if (!addition.StartsWith("&", StringComparison.Ordinal) && query.Length > 0) + { + addition = "&" + addition; + } + urlBuilder.Query = query + addition; + } + else + { + var path = url.AbsolutePath; + if (path == "/") path = ""; + if (!addition.StartsWith("/", StringComparison.Ordinal)) addition = "/" + addition; + + urlBuilder.Path = path + addition; + } + return ToUriString(urlBuilder.Uri); + } + return String.Concat(Value, addition); + } + + public override string ToString() + { + // Makes this look better in the debugger. + return Value; + } + + protected UriString(SerializationInfo info, StreamingContext context) + : this(GetSerializedValue(info)) + { + } + + static string GetSerializedValue(SerializationInfo info) + { + // First try to get the current way it's serialized, then fall back to the older way it's serialized. + string value; + try + { + value = info.GetValue("Value", typeof(string)) as string; + } + catch (SerializationException) + { + value = info.GetValue("uriString", typeof(string)) as string; + } + + return value; + } + + static string NormalizePath(string path) + { + return path?.Replace('\\', '/'); + } + + static string GetRepositoryName(string repositoryNameSegment) + { + if (String.IsNullOrEmpty(repositoryNameSegment) + || repositoryNameSegment.Equals("/", StringComparison.Ordinal)) + { + return null; + } + + return repositoryNameSegment.TrimEnd('/').TrimEnd(".git"); + } + + bool IEquatable.Equals(UriString other) + { + return other != null && ToString().Equals(other.ToString()); + } + } +} diff --git a/src/OctoRun/packages.config b/src/OctoRun/packages.config new file mode 100644 index 000000000..b37f38e52 --- /dev/null +++ b/src/OctoRun/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs index cb3a46c6a..a284af80b 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs @@ -21,6 +21,11 @@ public ApplicationManager(IMainThreadSynchronizationContext synchronizationConte Initialize(); } + public override NPath GetTool(string tool) + { + return Utility.GetTool(tool); + } + protected override void SetupMetrics() { SetupMetrics(Environment.UnityVersion, ApplicationCache.Instance.FirstRun); diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs index dea9fc30b..f80ab9f6f 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/EntryPoint.cs @@ -24,6 +24,7 @@ static EntryPoint() Logging.LogAdapter = new FileLogAdapter(tempEnv.LogPath); ServicePointManager.ServerCertificateValidationCallback = ServerCertificateValidationCallback; + ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; EditorApplication.update += Initialize; } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj index 97cf5479c..288cb3ef3 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj @@ -195,6 +195,9 @@ + + Tools\octorun.exe + diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs index 8b0e86bc2..cfaf0b767 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs @@ -49,6 +49,24 @@ public static Texture2D GetTextureFromColor(Color color) return result; } + + public static NPath GetTool(string filename, string filename2x = "") + { + var outfile = Application.temporaryCachePath.ToNPath().Combine(filename); + if (outfile.Exists()) + return outfile; + + var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("GitHub.Unity.Tools." + filename); + if (stream != null) + { + var targetFile = new FileInfo(outfile); + using (var outstream = targetFile.OpenWrite()) + { + ZipHelper.Copy(stream, outstream, 8192, stream.Length, null, 0); + } + } + return outfile; + } } static class StreamExtensions diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Services/AuthenticationService.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Services/AuthenticationService.cs index 3d81553cf..c627615ee 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Services/AuthenticationService.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Services/AuthenticationService.cs @@ -10,7 +10,7 @@ class AuthenticationService public AuthenticationService(UriString host, IKeychain keychain) { - client = ApiClient.Create(host, keychain); + client = ApiClient.Create(host, keychain, EntryPoint.ApplicationManager.ProcessManager, EntryPoint.ApplicationManager.TaskManager, EntryPoint.ApplicationManager.LoginTool); } public void Login(string username, string password, Action twofaRequired, Action authResult) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PopupWindow.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PopupWindow.cs index 6eb91b501..1fdd82047 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PopupWindow.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PopupWindow.cs @@ -198,7 +198,7 @@ public IApiClient Client host = UriString.ToUriString(HostAddress.GitHubDotComHostAddress.WebUri); } - client = ApiClient.Create(host, Platform.Keychain); + client = ApiClient.Create(host, Platform.Keychain, Manager.ProcessManager, TaskManager, Manager.LoginTool); } return client; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs index 99ab79516..895842cde 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs @@ -53,7 +53,7 @@ public IApiClient Client host = UriString.ToUriString(HostAddress.GitHubDotComHostAddress.WebUri); } - client = ApiClient.Create(host, Platform.Keychain); + client = ApiClient.Create(host, Platform.Keychain, Manager.ProcessManager, TaskManager, Manager.LoginTool); } return client; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs index 54afa6a1e..b522531ff 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs @@ -416,7 +416,7 @@ private void SignOut(object obj) host = UriString.ToUriString(HostAddress.GitHubDotComHostAddress.WebUri); } - var apiClient = ApiClient.Create(host, Platform.Keychain); + var apiClient = ApiClient.Create(host, Platform.Keychain, null, null, null); apiClient.Logout(host); } From 66eb21e64199139b5efd18f33a68f0426ae1026d Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 15:26:57 +0100 Subject: [PATCH 0170/1008] Fix build and add dependencies of the tool --- src/GitHub.Api/Authentication/LoginManager.cs | 2 +- src/OctoRun/OctoRun.csproj | 4 ++-- src/OctoRun/Program.cs | 2 +- src/OctoRun/packages.config | 1 + .../Editor/GitHub.Unity/GitHub.Unity.csproj | 9 +++++++++ .../Assets/Editor/GitHub.Unity/Misc/Utility.cs | 15 ++++++++++++--- 6 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/GitHub.Api/Authentication/LoginManager.cs b/src/GitHub.Api/Authentication/LoginManager.cs index efad70dd9..db961428a 100644 --- a/src/GitHub.Api/Authentication/LoginManager.cs +++ b/src/GitHub.Api/Authentication/LoginManager.cs @@ -257,7 +257,7 @@ private async Task TryLogin( string password ) { - logger.Info("Login Username:{0}", username); + logger.Info("Login Username:{0} {1}", username, loginTool); ApplicationAuthorization auth = null; var loginTask = new SimpleListProcessTask(taskManager.Token, loginTool, $"login --host={host}"); diff --git a/src/OctoRun/OctoRun.csproj b/src/OctoRun/OctoRun.csproj index 8ea4869c8..7e4dd4491 100644 --- a/src/OctoRun/OctoRun.csproj +++ b/src/OctoRun/OctoRun.csproj @@ -39,8 +39,8 @@ True - False - ..\..\..\octokit.net\Octokit\bin\Debug\net45\Octokit.dll + ..\..\packages\Octokit.0.29.0\lib\net45\Octokit.dll + True diff --git a/src/OctoRun/Program.cs b/src/OctoRun/Program.cs index dd6cd4a32..680ac54fd 100644 --- a/src/OctoRun/Program.cs +++ b/src/OctoRun/Program.cs @@ -92,7 +92,7 @@ class Program { static void Main(string[] args) { - Logging.LogAdapter = new ConsoleLogAdapter(); + //Logging.LogAdapter = new ConsoleLogAdapter(); AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; diff --git a/src/OctoRun/packages.config b/src/OctoRun/packages.config index b37f38e52..c98040a1a 100644 --- a/src/OctoRun/packages.config +++ b/src/OctoRun/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj index 288cb3ef3..17ade194b 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj @@ -198,6 +198,15 @@ Tools\octorun.exe + + Tools\GitHub.Logging.dll + + + Tools\Mono.Options.dll + + + Tools\Octokit.dll + diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs index cfaf0b767..80ac058dd 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs @@ -50,13 +50,21 @@ public static Texture2D GetTextureFromColor(Color color) return result; } - public static NPath GetTool(string filename, string filename2x = "") + public static NPath GetTool(string tool) { - var outfile = Application.temporaryCachePath.ToNPath().Combine(filename); + var outfile = Application.temporaryCachePath.ToNPath().Combine(tool); + + if (tool == "octorun.exe") + { + GetTool("Mono.Options.dll"); + GetTool("GitHub.Logging.dll"); + GetTool("Octokit.dll"); + } + if (outfile.Exists()) return outfile; - var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("GitHub.Unity.Tools." + filename); + var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("GitHub.Unity.Tools." + tool); if (stream != null) { var targetFile = new FileInfo(outfile); @@ -65,6 +73,7 @@ public static NPath GetTool(string filename, string filename2x = "") ZipHelper.Copy(stream, outstream, 8192, stream.Length, null, 0); } } + Logging.GetLogger().Debug(outfile); return outfile; } } From e3b86a76b7ad839557b838a0dd8c3ea332203289 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 15:34:37 +0100 Subject: [PATCH 0171/1008] Fix path to executable --- src/GitHub.Api/NewTaskSystem/ProcessTask.cs | 10 +++++----- src/GitHub.Api/OutputProcessors/ProcessManager.cs | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/GitHub.Api/NewTaskSystem/ProcessTask.cs b/src/GitHub.Api/NewTaskSystem/ProcessTask.cs index b2967f2c9..3099a47ad 100644 --- a/src/GitHub.Api/NewTaskSystem/ProcessTask.cs +++ b/src/GitHub.Api/NewTaskSystem/ProcessTask.cs @@ -84,10 +84,10 @@ public void Run() { Process.ErrorDataReceived += (s, e) => { - //if (e.Data != null) - //{ - // Logger.Trace("ErrorData \"" + (e.Data == null ? "'null'" : e.Data) + "\""); - //} + //if (e.Data != null) + //{ + // Logger.Trace("ErrorData \"" + (e.Data == null ? "'null'" : e.Data) + "\""); + //} string encodedData = null; if (e.Data != null) @@ -503,6 +503,6 @@ public SimpleListProcessTask(CancellationToken token, string arguments, IOutputP this.arguments = arguments; } - public override string ProcessName => fullPathToExecutable?.FileName; + public override string ProcessName => fullPathToExecutable; public override string ProcessArguments => arguments; }} \ No newline at end of file diff --git a/src/GitHub.Api/OutputProcessors/ProcessManager.cs b/src/GitHub.Api/OutputProcessors/ProcessManager.cs index 79bd83135..bf8711cc2 100644 --- a/src/GitHub.Api/OutputProcessors/ProcessManager.cs +++ b/src/GitHub.Api/OutputProcessors/ProcessManager.cs @@ -41,6 +41,8 @@ public T Configure(T processTask, NPath executable = null, string arguments = StandardErrorEncoding = Encoding.UTF8 }; + if (!executable.IsRelative) + workingDirectory = executable.Parent; gitEnvironment.Configure(startInfo, workingDirectory ?? environment.RepositoryPath); if (executable.IsRelative) From 2ede40f38ab0c1c0ec599e1f0a10609841966125 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 15:37:16 +0100 Subject: [PATCH 0172/1008] Need to close after writing --- src/GitHub.Api/Authentication/LoginManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/GitHub.Api/Authentication/LoginManager.cs b/src/GitHub.Api/Authentication/LoginManager.cs index db961428a..d0fcc84dd 100644 --- a/src/GitHub.Api/Authentication/LoginManager.cs +++ b/src/GitHub.Api/Authentication/LoginManager.cs @@ -266,6 +266,7 @@ string password { proc.StandardInput.WriteLine(username); proc.StandardInput.WriteLine(password); + proc.StandardInput.Close(); }; var ret = await loginTask.StartAwait(); if (ret.Count == 0) @@ -313,6 +314,7 @@ string code proc.StandardInput.WriteLine(username); proc.StandardInput.WriteLine(password); proc.StandardInput.WriteLine(code); + proc.StandardInput.Close(); }; var ret = await loginTask.StartAwait(); if (ret.Count == 0) From 92547badf890b869eede1731cd93cec1fdbc90db Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 16:02:48 +0100 Subject: [PATCH 0173/1008] Make sure we're on tls 12 --- src/OctoRun/Program.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/OctoRun/Program.cs b/src/OctoRun/Program.cs index 680ac54fd..c149ba868 100644 --- a/src/OctoRun/Program.cs +++ b/src/OctoRun/Program.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Net; using System.Threading.Tasks; using static OctoRun.LoginManager; @@ -94,6 +95,8 @@ static void Main(string[] args) { //Logging.LogAdapter = new ConsoleLogAdapter(); + ServicePointManager.ServerCertificateValidationCallback = (sender, chain, cert, errors) => true; + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; var opts = new OptionSet(); From f76d78cbe2503f34911249312b97666ef1bc41b1 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 16:03:16 +0100 Subject: [PATCH 0174/1008] Cosmetic tweak --- src/GitHub.Api/NewTaskSystem/ProcessTask.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/GitHub.Api/NewTaskSystem/ProcessTask.cs b/src/GitHub.Api/NewTaskSystem/ProcessTask.cs index 3099a47ad..03646906a 100644 --- a/src/GitHub.Api/NewTaskSystem/ProcessTask.cs +++ b/src/GitHub.Api/NewTaskSystem/ProcessTask.cs @@ -505,4 +505,5 @@ public SimpleListProcessTask(CancellationToken token, string arguments, IOutputP public override string ProcessName => fullPathToExecutable; public override string ProcessArguments => arguments; - }} \ No newline at end of file + } +} \ No newline at end of file From c14d3f59733e206e067ca1b58c0de786b25dff05 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 16:22:59 +0100 Subject: [PATCH 0175/1008] Bump version to 0.27.0 --- common/SolutionInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/SolutionInfo.cs b/common/SolutionInfo.cs index 902f73e57..bbde9c488 100644 --- a/common/SolutionInfo.cs +++ b/common/SolutionInfo.cs @@ -31,6 +31,6 @@ namespace System { internal static class AssemblyVersionInformation { - internal const string Version = "0.26.1"; + internal const string Version = "0.27.0"; } } From 86f2e2318e5cf88fd3c66b39380b8fcd9aaec8ed Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 16:31:28 +0100 Subject: [PATCH 0176/1008] Need to target 4.6 for mono to compile it --- src/OctoRun/OctoRun.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OctoRun/OctoRun.csproj b/src/OctoRun/OctoRun.csproj index 7e4dd4491..b72ec6fe6 100644 --- a/src/OctoRun/OctoRun.csproj +++ b/src/OctoRun/OctoRun.csproj @@ -9,7 +9,7 @@ Properties OctoRun octorun - v4.5.2 + v4.6.1 512 true Internal From 9de6b3d587256494b69feb581ad8ae4e3feaca5f Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 16:39:27 +0100 Subject: [PATCH 0177/1008] Make sure the build of OctoRun happens before the rest with the correct configuration --- common/properties.props | 3 ++- package.cmd | 3 +++ package.sh | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/common/properties.props b/common/properties.props index 9d7fd40c6..c6eaf184b 100644 --- a/common/properties.props +++ b/common/properties.props @@ -10,6 +10,7 @@ C:\Program Files\Unity\Editor\Data\Managed\ C:\Program Files (x86)\Unity\Editor\Data\Managed\ \Applications\Unity\Unity.app\Contents\Managed\ - Debug + Debug + $(Configuration) \ No newline at end of file diff --git a/package.cmd b/package.cmd index e25ddbd41..e71dbbb66 100644 --- a/package.cmd +++ b/package.cmd @@ -39,6 +39,9 @@ if not exist "%Unity%" ( cd .. call common\nuget.exe restore GitHub.Unity.sln + echo xbuild GitHub.Unity.sln /target:OctoRun /property:Configuration=%Configuration% + call xbuild GitHub.Unity.sln /target:OctoRun /property:Configuration=%Configuration% + echo xbuild GitHub.Unity.sln /property:Configuration=%Configuration% call xbuild GitHub.Unity.sln /property:Configuration=%Configuration% diff --git a/package.sh b/package.sh index ca09bd5e5..b2ce61ee9 100755 --- a/package.sh +++ b/package.sh @@ -51,6 +51,7 @@ else nuget restore GitHub.Unity.sln fi +xbuild GitHub.Unity.sln /target:OctoRun /property:Configuration=$Configuration xbuild GitHub.Unity.sln /property:Configuration=$Configuration rm -f unity/PackageProject/Assets/Plugins/GitHub/Editor/deleteme* From f3516a898a4e3406a44ba7451e6acec0337cfacd Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 16:40:15 +0100 Subject: [PATCH 0178/1008] Bump version to 0.26.2 --- common/SolutionInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/SolutionInfo.cs b/common/SolutionInfo.cs index bbde9c488..a32f7ba47 100644 --- a/common/SolutionInfo.cs +++ b/common/SolutionInfo.cs @@ -31,6 +31,6 @@ namespace System { internal static class AssemblyVersionInformation { - internal const string Version = "0.27.0"; + internal const string Version = "0.26.2"; } } From 2f6b28ba3f1b105a5274812371c5280b8fa35275 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 16:46:02 +0100 Subject: [PATCH 0179/1008] Place the tools in a known location independent of project --- src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs index 80ac058dd..e3da709c9 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs @@ -52,7 +52,8 @@ public static Texture2D GetTextureFromColor(Color color) public static NPath GetTool(string tool) { - var outfile = Application.temporaryCachePath.ToNPath().Combine(tool); + var outfile = EntryPoint.Environment.UserCachePath.Combine("tools", tool); + outfile.EnsureParentDirectoryExists(); if (tool == "octorun.exe") { From 85b11e7d7fa3f2df411eb4f131fa57ff095a3458 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 17:20:21 +0100 Subject: [PATCH 0180/1008] Build octorun before anything else in appveyor --- appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index a5d0c4580..9a1098d41 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -43,6 +43,9 @@ install: nuget restore GitHub.Unity.sln +before_build: + - cmd: msbuild GitHub.Unity.sln /target:OctoRun /Configuration:Release + assembly_info: patch: false file: common\SolutionInfo.cs From bfc3436d3d343baa4c7e5d9516e8387b9c31bf3e Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 17:24:20 +0100 Subject: [PATCH 0181/1008] Call msbuild correctly, doh --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 9a1098d41..2bcf0501c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -44,7 +44,7 @@ install: nuget restore GitHub.Unity.sln before_build: - - cmd: msbuild GitHub.Unity.sln /target:OctoRun /Configuration:Release + - cmd: msbuild GitHub.Unity.sln /target:OctoRun /property:Configuration=Release assembly_info: patch: false From 5b5ca253268e48ff806cb1f0f72e59bc8fec3262 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 18:00:16 +0100 Subject: [PATCH 0182/1008] Fix breakage in process running --- src/GitHub.Api/Authentication/LoginManager.cs | 2 +- src/GitHub.Api/OutputProcessors/ProcessManager.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/GitHub.Api/Authentication/LoginManager.cs b/src/GitHub.Api/Authentication/LoginManager.cs index d0fcc84dd..44ad79f60 100644 --- a/src/GitHub.Api/Authentication/LoginManager.cs +++ b/src/GitHub.Api/Authentication/LoginManager.cs @@ -261,7 +261,7 @@ string password ApplicationAuthorization auth = null; var loginTask = new SimpleListProcessTask(taskManager.Token, loginTool, $"login --host={host}"); - loginTask.Configure(processManager, true); + loginTask.Configure(processManager, workingDirectory: loginTool.Parent, withInput: true); loginTask.OnStartProcess += proc => { proc.StandardInput.WriteLine(username); diff --git a/src/GitHub.Api/OutputProcessors/ProcessManager.cs b/src/GitHub.Api/OutputProcessors/ProcessManager.cs index bf8711cc2..79bd83135 100644 --- a/src/GitHub.Api/OutputProcessors/ProcessManager.cs +++ b/src/GitHub.Api/OutputProcessors/ProcessManager.cs @@ -41,8 +41,6 @@ public T Configure(T processTask, NPath executable = null, string arguments = StandardErrorEncoding = Encoding.UTF8 }; - if (!executable.IsRelative) - workingDirectory = executable.Parent; gitEnvironment.Configure(startInfo, workingDirectory ?? environment.RepositoryPath); if (executable.IsRelative) From d2f70fdfbb153dfaad4540df1900aa15c897be34 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 23 Feb 2018 18:02:42 +0100 Subject: [PATCH 0183/1008] Missed one --- src/GitHub.Api/Authentication/LoginManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitHub.Api/Authentication/LoginManager.cs b/src/GitHub.Api/Authentication/LoginManager.cs index 44ad79f60..7995b897e 100644 --- a/src/GitHub.Api/Authentication/LoginManager.cs +++ b/src/GitHub.Api/Authentication/LoginManager.cs @@ -308,7 +308,7 @@ string code ApplicationAuthorization auth = null; var loginTask = new SimpleListProcessTask(taskManager.Token, loginTool, $"login --host={host} --2fa"); - loginTask.Configure(processManager, true); + loginTask.Configure(processManager, workingDirectory: loginTool.Parent, withInput: true); loginTask.OnStartProcess += proc => { proc.StandardInput.WriteLine(username); From 0080d3dfd745eca707ccda04213ebeaca4116a9c Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 26 Feb 2018 13:34:32 -0500 Subject: [PATCH 0184/1008] Ignoring a test from AppVeyor --- src/tests/IntegrationTests/Installer/GitInstallerTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs index 900b428e3..da8824978 100644 --- a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs +++ b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs @@ -35,6 +35,7 @@ public override void TestFixtureTearDown() } [Test] + [Category("DoNotRunOnAppVeyor")] public void GitInstallTest() { var gitInstallationPath = TestBasePath.Combine("GitInstall").CreateDirectory(); From eb3c65c7bf091644b39276f4758dfda3a9d8375e Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 27 Feb 2018 10:10:50 -0500 Subject: [PATCH 0185/1008] Discovering UserCachePath --- src/GitHub.Api/Application/ApplicationManagerBase.cs | 3 +-- src/GitHub.Api/Installer/GitInstaller.cs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 61894c369..6920afd60 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -72,8 +72,7 @@ public void Run(bool firstRun) } }); - var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); - var installDetails = new GitInstallDetails(applicationDataPath, true); + var installDetails = new GitInstallDetails(Environment.UserCachePath, true); var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails); // if successful, continue with environment initialization, otherwise try to find an existing git installation diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 8b303f55b..073742bd1 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -25,11 +25,11 @@ class GitInstallDetails private readonly bool onWindows; - public GitInstallDetails(NPath applicationDataPath, bool onWindows) + public GitInstallDetails(NPath pluginDataPath, bool onWindows) { this.onWindows = onWindows; - PluginDataPath = applicationDataPath.Combine(ApplicationInfo.ApplicationName); + PluginDataPath = pluginDataPath; var gitInstallPath = PluginDataPath.Combine(PackageNameWithVersion); GitInstallationPath = gitInstallPath; From b69605d2659f08a296614189ab17e42393393ab3 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 27 Feb 2018 12:08:04 -0500 Subject: [PATCH 0186/1008] Fix GitLock's Default member The default value will be 0 not -1 --- src/GitHub.Api/Git/GitLock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitHub.Api/Git/GitLock.cs b/src/GitHub.Api/Git/GitLock.cs index 1267e7af4..f604a0fdf 100644 --- a/src/GitHub.Api/Git/GitLock.cs +++ b/src/GitHub.Api/Git/GitLock.cs @@ -5,7 +5,7 @@ namespace GitHub.Unity [Serializable] public struct GitLock { - public static GitLock Default = new GitLock { ID = -1 }; + public static GitLock Default = new GitLock(); public int ID; public string Path; From 314d61ea7ebafebf5df00e162d5ac0d563e4508c Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 27 Feb 2018 12:09:41 -0500 Subject: [PATCH 0187/1008] Adding LfsLocksModificationProcessor --- .../Editor/GitHub.Unity/ApplicationManager.cs | 1 + .../Editor/GitHub.Unity/GitHub.Unity.csproj | 1 + .../UI/LfsLocksModificationProcessor.cs | 107 ++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/UI/LfsLocksModificationProcessor.cs diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs index c5fcfd00c..bcf9702ca 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs @@ -31,6 +31,7 @@ protected override void InitializeUI() Logger.Trace("Restarted {0}", Environment.Repository); EnvironmentCache.Instance.Flush(); + LfsLocksModificationProcessor.Initialize(Environment.Repository); ProjectWindowInterface.Initialize(Environment.Repository); var window = Window.GetWindow(); if (window != null) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj index 1bc293176..43466162c 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/GitHub.Unity.csproj @@ -94,6 +94,7 @@ + diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/LfsLocksModificationProcessor.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/LfsLocksModificationProcessor.cs new file mode 100644 index 000000000..328a620fe --- /dev/null +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/LfsLocksModificationProcessor.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using System.Linq; +using GitHub.Logging; +using UnityEditor; + +namespace GitHub.Unity +{ + class LfsLocksModificationProcessor : UnityEditor.AssetModificationProcessor + { + private static ILogging logger; + private static ILogging Logger { get { return logger = logger ?? LogHelper.GetLogger(); } } + + private static IRepository repository; + + private static List locks = new List(); + + private static CacheUpdateEvent lastLocksChangedEvent; + + public static void Initialize(IRepository repo) + { + Logger.Trace("Initialize HasRepository:{0}", repo != null); + + repository = repo; + + if (repository != null) + { + repository.LocksChanged += RepositoryOnLocksChanged; + repository.CheckLocksChangedEvent(lastLocksChangedEvent); + } + } + + private static void RepositoryOnLocksChanged(CacheUpdateEvent cacheUpdateEvent) + { + if (!lastLocksChangedEvent.Equals(cacheUpdateEvent)) + { + lastLocksChangedEvent = cacheUpdateEvent; + locks = repository.CurrentLocks; + } + } + + public static string[] OnWillSaveAssets(string[] paths) + { + Logger.Trace("OnWillSaveAssets: [{0}]", string.Join(", ", paths)); + return paths; + } + + public static AssetMoveResult OnWillMoveAsset(string oldPath, string newPath) + { + Logger.Trace("OnWillMoveAsset:{0}->{1}", oldPath, newPath); + + var result = AssetMoveResult.DidNotMove; + if (IsLocked(oldPath)) + { + result = AssetMoveResult.FailedMove; + } + else if (IsLocked(newPath)) + { + result = AssetMoveResult.FailedMove; + } + return result; + } + + public static AssetDeleteResult OnWillDeleteAsset(string assetPath, RemoveAssetOptions option) + { + Logger.Trace("OnWillDeleteAsset:{0}", assetPath); + + if (IsLocked(assetPath)) + { + return AssetDeleteResult.FailedDelete; + } + return AssetDeleteResult.DidNotDelete; + } + + public static bool IsOpenForEdit(string assetPath, out string message) + { + Logger.Trace("IsOpenForEdit:{0}", assetPath); + + if (IsLocked(assetPath)) + { + message = "File is locked for editing!"; + return false; + } + else + { + message = null; + return true; + } + } + + private static bool IsLocked(string assetPath) + { + if(repository != null) + { + var repositoryPath = EntryPoint.Environment.GetRepositoryPath(assetPath.ToNPath()); + var gitLock = locks.FirstOrDefault(@lock => @lock.Path == repositoryPath); + if (!gitLock.Equals(GitLock.Default)) + { + Logger.Trace("Lock found on: {0}", assetPath); + + //TODO: Check user and return true + } + } + + return false; + } + } +} \ No newline at end of file From 53de0aa74934c73dd12a2e03a26654e26b0533d4 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 27 Feb 2018 13:38:27 -0500 Subject: [PATCH 0188/1008] Initial project from 'yo nodejs-cli-typescript' --- octorun/.gitignore | 2 + octorun/LICENSE | 21 ++ octorun/bin/octorun | 3 + octorun/bin/octorun-write | 3 + octorun/dist/bin/app-write.d.ts | 7 + octorun/dist/bin/app-write.js | 30 ++ octorun/dist/bin/app.d.ts | 6 + octorun/dist/bin/app.js | 18 + octorun/dist/writer.d.ts | 3 + octorun/dist/writer.js | 8 + octorun/package-lock.json | 609 ++++++++++++++++++++++++++++++++ octorun/package.json | 43 +++ octorun/src/bin/app-write.ts | 39 ++ octorun/src/bin/app.ts | 23 ++ octorun/src/writer.ts | 7 + octorun/test/writer-spec.ts | 34 ++ octorun/tsconfig.json | 21 ++ 17 files changed, 877 insertions(+) create mode 100644 octorun/.gitignore create mode 100644 octorun/LICENSE create mode 100644 octorun/bin/octorun create mode 100644 octorun/bin/octorun-write create mode 100644 octorun/dist/bin/app-write.d.ts create mode 100644 octorun/dist/bin/app-write.js create mode 100644 octorun/dist/bin/app.d.ts create mode 100644 octorun/dist/bin/app.js create mode 100644 octorun/dist/writer.d.ts create mode 100644 octorun/dist/writer.js create mode 100644 octorun/package-lock.json create mode 100644 octorun/package.json create mode 100644 octorun/src/bin/app-write.ts create mode 100644 octorun/src/bin/app.ts create mode 100644 octorun/src/writer.ts create mode 100644 octorun/test/writer-spec.ts create mode 100644 octorun/tsconfig.json diff --git a/octorun/.gitignore b/octorun/.gitignore new file mode 100644 index 000000000..93f136199 --- /dev/null +++ b/octorun/.gitignore @@ -0,0 +1,2 @@ +node_modules +npm-debug.log diff --git a/octorun/LICENSE b/octorun/LICENSE new file mode 100644 index 000000000..0776bd363 --- /dev/null +++ b/octorun/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/octorun/bin/octorun b/octorun/bin/octorun new file mode 100644 index 000000000..81c553ba0 --- /dev/null +++ b/octorun/bin/octorun @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('../dist/bin/app.js'); diff --git a/octorun/bin/octorun-write b/octorun/bin/octorun-write new file mode 100644 index 000000000..62ead2886 --- /dev/null +++ b/octorun/bin/octorun-write @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('../dist/bin/app-write.js'); diff --git a/octorun/dist/bin/app-write.d.ts b/octorun/dist/bin/app-write.d.ts new file mode 100644 index 000000000..b6e272292 --- /dev/null +++ b/octorun/dist/bin/app-write.d.ts @@ -0,0 +1,7 @@ +export declare class Write { + private program; + private package; + private writer; + constructor(); + initialize(): void; +} diff --git a/octorun/dist/bin/app-write.js b/octorun/dist/bin/app-write.js new file mode 100644 index 000000000..d3b06281b --- /dev/null +++ b/octorun/dist/bin/app-write.js @@ -0,0 +1,30 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const commander = require("commander"); +const writer_1 = require("../writer"); +class Write { + constructor() { + this.program = commander; + this.package = require('../../package.json'); + this.writer = new writer_1.Writer(); + } + initialize() { + this.program + .version(this.package.version) + .option('-m, --message [value]', 'Say hello!') + .parse(process.argv); + if (this.program.message != null) { + if (typeof this.program.message !== 'string') { + this.writer.write(); + } + else { + this.writer.write(this.program.message); + } + process.exit(); + } + this.program.help(); + } +} +exports.Write = Write; +let app = new Write(); +app.initialize(); diff --git a/octorun/dist/bin/app.d.ts b/octorun/dist/bin/app.d.ts new file mode 100644 index 000000000..65223902d --- /dev/null +++ b/octorun/dist/bin/app.d.ts @@ -0,0 +1,6 @@ +export declare class App { + private program; + private package; + constructor(); + initialize(): void; +} diff --git a/octorun/dist/bin/app.js b/octorun/dist/bin/app.js new file mode 100644 index 000000000..28bcd5ebe --- /dev/null +++ b/octorun/dist/bin/app.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const commander = require("commander"); +class App { + constructor() { + this.program = commander; + this.package = require('../../package.json'); + } + initialize() { + this.program + .version(this.package.version) + .command('write [message]', 'say hello!') + .parse(process.argv); + } +} +exports.App = App; +let app = new App(); +app.initialize(); diff --git a/octorun/dist/writer.d.ts b/octorun/dist/writer.d.ts new file mode 100644 index 000000000..8373b156f --- /dev/null +++ b/octorun/dist/writer.d.ts @@ -0,0 +1,3 @@ +export declare class Writer { + write(message?: String): void; +} diff --git a/octorun/dist/writer.js b/octorun/dist/writer.js new file mode 100644 index 000000000..cc6f2a672 --- /dev/null +++ b/octorun/dist/writer.js @@ -0,0 +1,8 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +class Writer { + write(message = "Hello World!") { + console.log(message); + } +} +exports.Writer = Writer; diff --git a/octorun/package-lock.json b/octorun/package-lock.json new file mode 100644 index 000000000..0a2cf1867 --- /dev/null +++ b/octorun/package-lock.json @@ -0,0 +1,609 @@ +{ + "name": "octorun", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/chai": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.2.tgz", + "integrity": "sha512-D8uQwKYUw2KESkorZ27ykzXgvkDJYXVEihGklgfp5I4HUP8D6IxtcdLTMB1emjQiWzV7WZ5ihm1cxIzVwjoleQ==", + "dev": true + }, + "@types/commander": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/@types/commander/-/commander-2.12.2.tgz", + "integrity": "sha512-0QEFiR8ljcHp9bAbWxecjVRuAMr16ivPiGOw6KFQBVrVd0RQIcM3xKdRisH2EDWgVWujiYtHwhSkSUoAAGzH7Q==", + "dev": true, + "requires": { + "commander": "2.14.1" + } + }, + "@types/mocha": { + "version": "2.2.48", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.48.tgz", + "integrity": "sha512-nlK/iyETgafGli8Zh9zJVCTicvU3iajSkRwOh3Hhiva598CMqNJ4NcVCGMTGKpGpTYj/9R8RLzS9NAykSSCqGw==", + "dev": true + }, + "@types/node": { + "version": "7.0.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.55.tgz", + "integrity": "sha512-diCxfWNT4g2UM9Y+BPgy4s3egcZ2qOXc0mXLauvbsBUq9SBKQfh0SmuEUEhJVFZt/p6UDsjg1s2EgfM6OSlp4g==", + "dev": true + }, + "@types/sinon": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-2.3.7.tgz", + "integrity": "sha512-w+LjztaZbgZWgt/y/VMP5BUAWLtSyoIJhXyW279hehLPyubDoBNwvhcj3WaSptcekuKYeTCVxrq60rdLc6ImJA==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "chai": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", + "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", + "dev": true, + "requires": { + "assertion-error": "1.1.0", + "check-error": "1.0.2", + "deep-eql": "3.0.1", + "get-func-name": "2.0.0", + "pathval": "1.1.0", + "type-detect": "4.0.8" + } + }, + "chalk": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", + "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "5.2.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", + "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", + "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "formatio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", + "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", + "dev": true, + "requires": { + "samsam": "1.3.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", + "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "dev": true, + "requires": { + "parse-passwd": "1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "lolex": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", + "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", + "dev": true + }, + "make-error": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", + "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", + "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.8", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "he": "1.1.1", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "dependencies": { + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "7.1.1" + } + }, + "samsam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", + "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", + "dev": true + }, + "sinon": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.4.1.tgz", + "integrity": "sha512-vFTrO9Wt0ECffDYIPSP/E5bBugt0UjcBQOfQUMh66xzkyPEnhl/vM2LRZi2ajuTdkH07sA6DzrM6KvdvGIH8xw==", + "dev": true, + "requires": { + "diff": "3.2.0", + "formatio": "1.2.0", + "lolex": "1.6.0", + "native-promise-only": "0.8.1", + "path-to-regexp": "1.7.0", + "samsam": "1.3.0", + "text-encoding": "0.6.4", + "type-detect": "4.0.8" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + }, + "text-encoding": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", + "dev": true + }, + "ts-node": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-3.3.0.tgz", + "integrity": "sha1-wTxqMCTjC+EYDdUwOPwgkonUv2k=", + "dev": true, + "requires": { + "arrify": "1.0.1", + "chalk": "2.3.1", + "diff": "3.2.0", + "make-error": "1.3.4", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18", + "tsconfig": "6.0.0", + "v8flags": "3.0.2", + "yn": "2.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "tsconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-6.0.0.tgz", + "integrity": "sha1-aw6DdgA9evGGT434+J3QBZ/80DI=", + "dev": true, + "requires": { + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "typescript": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz", + "integrity": "sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw==", + "dev": true + }, + "v8flags": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.2.tgz", + "integrity": "sha512-6sgSKoFw1UpUPd3cFdF7QGnrH6tDeBgW1F3v9gy8gLY0mlbiBXq8soy8aQpY6xeeCjH5K+JvC62Acp7gtl7wWA==", + "dev": true, + "requires": { + "homedir-polyfill": "1.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + } + } +} diff --git a/octorun/package.json b/octorun/package.json new file mode 100644 index 000000000..7f4888d0d --- /dev/null +++ b/octorun/package.json @@ -0,0 +1,43 @@ +{ + "name": "octorun", + "version": "0.1.0", + "description": "", + "repository": "", + "license": "MIT", + "scripts": { + "clean": "rimraf dist", + "build": "npm run clean && tsc --pretty", + "test": "npm run build && mocha --compilers ts:ts-node/register --recursive test/**/*-spec.ts", + "watch": "npm run build -- --watch", + "watch:test": "npm run test -- --watch" + }, + "author": { + "name": "Stanley Goldman", + "email": "Stanley.Goldman@gmail.com" + }, + "main": "dist/bin/app.js", + "typings": "dist/bin/app.d.ts", + "bin": { + "octorun": "bin/octorun" + }, + "files": [ + "bin", + "dist" + ], + "devDependencies": { + "@types/chai": "^4.0.0", + "@types/commander": "^2.3.31", + "@types/mocha": "^2.2.39", + "@types/node": "^7.0.5", + "@types/sinon": "^2.3.0", + "chai": "^4.0.1", + "mocha": "^3.2.0", + "rimraf": "^2.6.1", + "sinon": "^2.3.2", + "ts-node": "^3.0.4", + "typescript": "^2.2.1" + }, + "dependencies": { + "commander": "^2.9.0" + } +} diff --git a/octorun/src/bin/app-write.ts b/octorun/src/bin/app-write.ts new file mode 100644 index 000000000..743f97f54 --- /dev/null +++ b/octorun/src/bin/app-write.ts @@ -0,0 +1,39 @@ +import * as commander from 'commander'; +import { Writer } from '../writer'; + +export class Write { + + private program: commander.CommanderStatic; + private package: any; + private writer: Writer; + + constructor() { + this.program = commander; + this.package = require('../../package.json'); + this.writer = new Writer(); + } + + public initialize() { + this.program + .version(this.package.version) + .option('-m, --message [value]', 'Say hello!') + .parse(process.argv); + + if (this.program.message != null) { + + if (typeof this.program.message !== 'string') { + this.writer.write(); + } else { + this.writer.write(this.program.message); + } + + process.exit(); + } + + this.program.help(); + } + +} + +let app = new Write(); +app.initialize(); diff --git a/octorun/src/bin/app.ts b/octorun/src/bin/app.ts new file mode 100644 index 000000000..53feb85a4 --- /dev/null +++ b/octorun/src/bin/app.ts @@ -0,0 +1,23 @@ +import * as commander from 'commander'; + +export class App { + + private program: commander.CommanderStatic; + private package: any; + + constructor() { + this.program = commander; + this.package = require('../../package.json'); + } + + public initialize() { + this.program + .version(this.package.version) + .command('write [message]', 'say hello!') + .parse(process.argv); + } + +} + +let app = new App(); +app.initialize(); diff --git a/octorun/src/writer.ts b/octorun/src/writer.ts new file mode 100644 index 000000000..2a15fdff9 --- /dev/null +++ b/octorun/src/writer.ts @@ -0,0 +1,7 @@ +export class Writer { + + public write(message: String = "Hello World!") { + console.log(message); + } + +} diff --git a/octorun/test/writer-spec.ts b/octorun/test/writer-spec.ts new file mode 100644 index 000000000..b85289ec6 --- /dev/null +++ b/octorun/test/writer-spec.ts @@ -0,0 +1,34 @@ +import { Writer } from '../src/writer'; +import * as chai from 'chai'; +import * as sinon from 'sinon'; + +const assert = chai.assert; + +describe('Writer', () => { + describe('#write()', () => { + it('should write a message', () => { + + let spy = sinon.spy(console, 'log'); + + var writer = new Writer(); + writer.write('I am being tested!'); + + assert(spy.calledWith('I am being tested!')); + + spy.restore(); + + }); + it('should write a default message', () => { + + let spy = sinon.spy(console, 'log'); + + var writer = new Writer(); + writer.write(); + + assert(spy.calledWith('Hello World!')); + + spy.restore(); + + }); + }); +}); diff --git a/octorun/tsconfig.json b/octorun/tsconfig.json new file mode 100644 index 000000000..7706353b9 --- /dev/null +++ b/octorun/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "target": "es6", + "declaration": true, + "module": "commonjs", + "moduleResolution": "node", + "noImplicitAny": true, + "outDir": "./dist", + "preserveConstEnums": true, + "removeComments": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "!node_modules/@types", + "test/**/*-spec.ts" + ] +} From 61d370b777b1597f833cbecd3ac9f054a392af71 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 27 Feb 2018 13:41:29 -0500 Subject: [PATCH 0189/1008] Adding octokit --- octorun/package.json | 83 ++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/octorun/package.json b/octorun/package.json index 7f4888d0d..d00f413d9 100644 --- a/octorun/package.json +++ b/octorun/package.json @@ -1,43 +1,44 @@ { - "name": "octorun", - "version": "0.1.0", - "description": "", - "repository": "", - "license": "MIT", - "scripts": { - "clean": "rimraf dist", - "build": "npm run clean && tsc --pretty", - "test": "npm run build && mocha --compilers ts:ts-node/register --recursive test/**/*-spec.ts", - "watch": "npm run build -- --watch", - "watch:test": "npm run test -- --watch" - }, - "author": { - "name": "Stanley Goldman", - "email": "Stanley.Goldman@gmail.com" - }, - "main": "dist/bin/app.js", - "typings": "dist/bin/app.d.ts", - "bin": { - "octorun": "bin/octorun" - }, - "files": [ - "bin", - "dist" - ], - "devDependencies": { - "@types/chai": "^4.0.0", - "@types/commander": "^2.3.31", - "@types/mocha": "^2.2.39", - "@types/node": "^7.0.5", - "@types/sinon": "^2.3.0", - "chai": "^4.0.1", - "mocha": "^3.2.0", - "rimraf": "^2.6.1", - "sinon": "^2.3.2", - "ts-node": "^3.0.4", - "typescript": "^2.2.1" - }, - "dependencies": { - "commander": "^2.9.0" - } + "name": "octorun", + "version": "0.1.0", + "description": "", + "repository": "", + "license": "MIT", + "scripts": { + "clean": "rimraf dist", + "build": "npm run clean && tsc --pretty", + "test": "npm run build && mocha --compilers ts:ts-node/register --recursive test/**/*-spec.ts", + "watch": "npm run build -- --watch", + "watch:test": "npm run test -- --watch" + }, + "author": { + "name": "Stanley Goldman", + "email": "Stanley.Goldman@gmail.com" + }, + "main": "dist/bin/app.js", + "typings": "dist/bin/app.d.ts", + "bin": { + "octorun": "bin/octorun" + }, + "files": [ + "bin", + "dist" + ], + "devDependencies": { + "@types/chai": "^4.0.0", + "@types/commander": "^2.3.31", + "@types/mocha": "^2.2.39", + "@types/node": "^7.0.5", + "@types/sinon": "^2.3.0", + "chai": "^4.0.1", + "mocha": "^3.2.0", + "rimraf": "^2.6.1", + "sinon": "^2.3.2", + "ts-node": "^3.0.4", + "typescript": "^2.2.1" + }, + "dependencies": { + "@octokit/rest": "^14.0.9", + "commander": "^2.9.0" + } } From 9f99333f6827f7ec242dce942445f06a6a0237fb Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 27 Feb 2018 14:22:35 -0500 Subject: [PATCH 0190/1008] Login command and Authenticator --- octorun/bin/octorun-login | 3 +++ octorun/dist/authenticator.d.ts | 5 +++++ octorun/dist/authenticator.js | 21 ++++++++++++++++++ octorun/dist/bin/app-login.d.ts | 7 ++++++ octorun/dist/bin/app-login.js | 23 ++++++++++++++++++++ octorun/src/authenticator.ts | 34 +++++++++++++++++++++++++++++ octorun/src/bin/app-login.ts | 38 +++++++++++++++++++++++++++++++++ 7 files changed, 131 insertions(+) create mode 100644 octorun/bin/octorun-login create mode 100644 octorun/dist/authenticator.d.ts create mode 100644 octorun/dist/authenticator.js create mode 100644 octorun/dist/bin/app-login.d.ts create mode 100644 octorun/dist/bin/app-login.js create mode 100644 octorun/src/authenticator.ts create mode 100644 octorun/src/bin/app-login.ts diff --git a/octorun/bin/octorun-login b/octorun/bin/octorun-login new file mode 100644 index 000000000..fe09da41a --- /dev/null +++ b/octorun/bin/octorun-login @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('../dist/bin/app-login.js'); diff --git a/octorun/dist/authenticator.d.ts b/octorun/dist/authenticator.d.ts new file mode 100644 index 000000000..3e80a0cb2 --- /dev/null +++ b/octorun/dist/authenticator.d.ts @@ -0,0 +1,5 @@ +export declare class Authenticator { + private github; + constructor(); + authenticate(): void; +} diff --git a/octorun/dist/authenticator.js b/octorun/dist/authenticator.js new file mode 100644 index 000000000..27e329d56 --- /dev/null +++ b/octorun/dist/authenticator.js @@ -0,0 +1,21 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const GitHub = require("@octokit/rest"); +class Authenticator { + constructor() { + this.github = new GitHub({ + timeout: 0, + requestMedia: 'application/vnd.github.v3+json', + headers: { + 'user-agent': 'octokit/rest.js v1.2.3' + }, + host: 'api.github.com', + pathPrefix: '', + protocol: 'https', + port: 443, + }); + } + authenticate() { + } +} +exports.Authenticator = Authenticator; diff --git a/octorun/dist/bin/app-login.d.ts b/octorun/dist/bin/app-login.d.ts new file mode 100644 index 000000000..1a4eeeebc --- /dev/null +++ b/octorun/dist/bin/app-login.d.ts @@ -0,0 +1,7 @@ +export declare class Write { + private program; + private package; + private authenticator; + constructor(); + initialize(): void; +} diff --git a/octorun/dist/bin/app-login.js b/octorun/dist/bin/app-login.js new file mode 100644 index 000000000..84edd3eec --- /dev/null +++ b/octorun/dist/bin/app-login.js @@ -0,0 +1,23 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const commander = require("commander"); +const authenticator_1 = require("../authenticator"); +class Write { + constructor() { + this.program = commander; + this.package = require('../../package.json'); + this.authenticator = new authenticator_1.Authenticator(); + } + initialize() { + this.program + .version(this.package.version) + .parse(process.argv); + if (this.program.message != null) { + process.exit(); + } + this.program.help(); + } +} +exports.Write = Write; +let app = new Write(); +app.initialize(); diff --git a/octorun/src/authenticator.ts b/octorun/src/authenticator.ts new file mode 100644 index 000000000..c30816126 --- /dev/null +++ b/octorun/src/authenticator.ts @@ -0,0 +1,34 @@ +//const octokit = require('@octokit/rest') + +import * as GitHub from '@octokit/rest'; + +export class Authenticator { + + private github: GitHub; + + constructor(){ + + //Listed defaults from https://github.com/octokit/rest.js#options + + this.github = new GitHub({ + timeout: 0, // 0 means no request timeout + requestMedia: 'application/vnd.github.v3+json', + headers: { + 'user-agent': 'octokit/rest.js v1.2.3' // v1.2.3 will be current version + }, + + // change for custom GitHub Enterprise URL + host: 'api.github.com', + pathPrefix: '', + protocol: 'https', + port: 443, + + // Node only: advanced request options can be passed as http(s) agent + //agent: undefined + }) + } + + public authenticate() { + + } +} diff --git a/octorun/src/bin/app-login.ts b/octorun/src/bin/app-login.ts new file mode 100644 index 000000000..5022eebd3 --- /dev/null +++ b/octorun/src/bin/app-login.ts @@ -0,0 +1,38 @@ +import * as commander from 'commander'; +import { Authenticator } from '../authenticator'; + +export class Write { + + private program: commander.CommanderStatic; + private package: any; + private authenticator: Authenticator; + + constructor() { + this.program = commander; + this.package = require('../../package.json'); + this.authenticator = new Authenticator(); + } + + public initialize() { + this.program + .version(this.package.version) + .parse(process.argv); + + if (this.program.message != null) { + + // if (typeof this.program.message !== 'string') { + // this.writer.write(); + // } else { + // this.writer.write(this.program.message); + // } + + process.exit(); + } + + this.program.help(); + } + +} + +let app = new Write(); +app.initialize(); From 5f0486004d3d4aeefcebb90c0373489897b4c568 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 27 Feb 2018 16:30:11 -0500 Subject: [PATCH 0191/1008] A chunk of octorun that should work --- octorun/.env.template | 2 + octorun/.gitignore | 1 + octorun/bin/octorun | 2 + octorun/dist/authenticator.d.ts | 2 +- octorun/dist/authenticator.js | 70 +++++++++++++++++++++++++++++---- octorun/dist/bin/app-login.js | 67 ++++++++++++++++++++++++++----- octorun/dist/bin/app-write.js | 19 ++++----- octorun/dist/bin/app.js | 18 +++++---- octorun/dist/configuration.d.ts | 5 +++ octorun/dist/configuration.js | 7 ++++ octorun/dist/writer.js | 14 ++++--- octorun/package.json | 4 +- octorun/src/authenticator.ts | 19 ++++++--- octorun/src/bin/app-login.ts | 12 +++--- octorun/src/bin/app.ts | 3 ++ octorun/src/configuration.ts | 6 +++ octorun/tsconfig.json | 39 +++++++++--------- 17 files changed, 217 insertions(+), 73 deletions(-) create mode 100644 octorun/.env.template create mode 100644 octorun/dist/configuration.d.ts create mode 100644 octorun/dist/configuration.js create mode 100644 octorun/src/configuration.ts diff --git a/octorun/.env.template b/octorun/.env.template new file mode 100644 index 000000000..7eaafeb53 --- /dev/null +++ b/octorun/.env.template @@ -0,0 +1,2 @@ +OCTOKIT_CLIENT_ID= +OCTOKIT_CLIENT_SECRET= \ No newline at end of file diff --git a/octorun/.gitignore b/octorun/.gitignore index 93f136199..ef4fcce9d 100644 --- a/octorun/.gitignore +++ b/octorun/.gitignore @@ -1,2 +1,3 @@ +.env node_modules npm-debug.log diff --git a/octorun/bin/octorun b/octorun/bin/octorun index 81c553ba0..6c0fe6d04 100644 --- a/octorun/bin/octorun +++ b/octorun/bin/octorun @@ -1,3 +1,5 @@ #!/usr/bin/env node +console.log("NodeJs", process.argv[0]); + require('../dist/bin/app.js'); diff --git a/octorun/dist/authenticator.d.ts b/octorun/dist/authenticator.d.ts index 3e80a0cb2..ba36c1983 100644 --- a/octorun/dist/authenticator.d.ts +++ b/octorun/dist/authenticator.d.ts @@ -1,5 +1,5 @@ export declare class Authenticator { private github; constructor(); - authenticate(): void; + createAndDeleteExistingApplicationAuthorization(input?: string): Promise; } diff --git a/octorun/dist/authenticator.js b/octorun/dist/authenticator.js index 27e329d56..38d60518c 100644 --- a/octorun/dist/authenticator.js +++ b/octorun/dist/authenticator.js @@ -1,8 +1,44 @@ "use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const GitHub = require("@octokit/rest"); -class Authenticator { - constructor() { +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +exports.__esModule = true; +var GitHub = require("@octokit/rest"); +var configuration_1 = require("./configuration"); +var Authenticator = (function () { + function Authenticator() { this.github = new GitHub({ timeout: 0, requestMedia: 'application/vnd.github.v3+json', @@ -12,10 +48,28 @@ class Authenticator { host: 'api.github.com', pathPrefix: '', protocol: 'https', - port: 443, + port: 443 }); } - authenticate() { - } -} + Authenticator.prototype.createAndDeleteExistingApplicationAuthorization = function (input) { + return __awaiter(this, void 0, void 0, function () { + var authParams; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + authParams = { + client_id: configuration_1.configuration.ClientId, + client_secret: configuration_1.configuration.ClientSecret, + scopes: ["user", "repo", "gist", "write:public_key"] + }; + return [4, this.github.authorization.getOrCreateAuthorizationForApp(authParams)]; + case 1: + _a.sent(); + return [2]; + } + }); + }); + }; + return Authenticator; +}()); exports.Authenticator = Authenticator; diff --git a/octorun/dist/bin/app-login.js b/octorun/dist/bin/app-login.js index 84edd3eec..afdf9fe8c 100644 --- a/octorun/dist/bin/app-login.js +++ b/octorun/dist/bin/app-login.js @@ -1,23 +1,70 @@ "use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const commander = require("commander"); -const authenticator_1 = require("../authenticator"); -class Write { - constructor() { +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +exports.__esModule = true; +var commander = require("commander"); +var authenticator_1 = require("../authenticator"); +var Write = (function () { + function Write() { this.program = commander; this.package = require('../../package.json'); this.authenticator = new authenticator_1.Authenticator(); } - initialize() { + Write.prototype.initialize = function () { + var _this = this; this.program .version(this.package.version) + .option('-l, --login') + .option('-t, --twoFactor') .parse(process.argv); - if (this.program.message != null) { + if (this.program.login) { + var blah = function () { return __awaiter(_this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2]; + }); + }); }; + process.exit(); + } + else if (this.program.twoFactor) { process.exit(); } this.program.help(); - } -} + }; + return Write; +}()); exports.Write = Write; -let app = new Write(); +var app = new Write(); app.initialize(); diff --git a/octorun/dist/bin/app-write.js b/octorun/dist/bin/app-write.js index d3b06281b..fd02ec270 100644 --- a/octorun/dist/bin/app-write.js +++ b/octorun/dist/bin/app-write.js @@ -1,14 +1,14 @@ "use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const commander = require("commander"); -const writer_1 = require("../writer"); -class Write { - constructor() { +exports.__esModule = true; +var commander = require("commander"); +var writer_1 = require("../writer"); +var Write = (function () { + function Write() { this.program = commander; this.package = require('../../package.json'); this.writer = new writer_1.Writer(); } - initialize() { + Write.prototype.initialize = function () { this.program .version(this.package.version) .option('-m, --message [value]', 'Say hello!') @@ -23,8 +23,9 @@ class Write { process.exit(); } this.program.help(); - } -} + }; + return Write; +}()); exports.Write = Write; -let app = new Write(); +var app = new Write(); app.initialize(); diff --git a/octorun/dist/bin/app.js b/octorun/dist/bin/app.js index 28bcd5ebe..10a9c9caf 100644 --- a/octorun/dist/bin/app.js +++ b/octorun/dist/bin/app.js @@ -1,18 +1,20 @@ "use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const commander = require("commander"); -class App { - constructor() { +exports.__esModule = true; +var commander = require("commander"); +var App = (function () { + function App() { this.program = commander; this.package = require('../../package.json'); } - initialize() { + App.prototype.initialize = function () { this.program .version(this.package.version) + .command('login [-h|-2fa]', 'Authenticate') .command('write [message]', 'say hello!') .parse(process.argv); - } -} + }; + return App; +}()); exports.App = App; -let app = new App(); +var app = new App(); app.initialize(); diff --git a/octorun/dist/configuration.d.ts b/octorun/dist/configuration.d.ts new file mode 100644 index 000000000..93e15f619 --- /dev/null +++ b/octorun/dist/configuration.d.ts @@ -0,0 +1,5 @@ +declare const configuration: { + ClientId: any; + ClientSecret: any; +}; +export { configuration }; diff --git a/octorun/dist/configuration.js b/octorun/dist/configuration.js new file mode 100644 index 000000000..1a3d3ed1c --- /dev/null +++ b/octorun/dist/configuration.js @@ -0,0 +1,7 @@ +"use strict"; +exports.__esModule = true; +var configuration = { + ClientId: process.env.OCTOKIT_CLIENT_ID, + ClientSecret: process.env.OCTOKIT_CLIENT_SECRET +}; +exports.configuration = configuration; diff --git a/octorun/dist/writer.js b/octorun/dist/writer.js index cc6f2a672..e5d55d015 100644 --- a/octorun/dist/writer.js +++ b/octorun/dist/writer.js @@ -1,8 +1,12 @@ "use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -class Writer { - write(message = "Hello World!") { - console.log(message); +exports.__esModule = true; +var Writer = (function () { + function Writer() { } -} + Writer.prototype.write = function (message) { + if (message === void 0) { message = "Hello World!"; } + console.log(message); + }; + return Writer; +}()); exports.Writer = Writer; diff --git a/octorun/package.json b/octorun/package.json index d00f413d9..c8dac5670 100644 --- a/octorun/package.json +++ b/octorun/package.json @@ -27,6 +27,7 @@ "devDependencies": { "@types/chai": "^4.0.0", "@types/commander": "^2.3.31", + "@types/dotenv": "^4.0.2", "@types/mocha": "^2.2.39", "@types/node": "^7.0.5", "@types/sinon": "^2.3.0", @@ -39,6 +40,7 @@ }, "dependencies": { "@octokit/rest": "^14.0.9", - "commander": "^2.9.0" + "commander": "^2.9.0", + "dotenv": "^5.0.1" } } diff --git a/octorun/src/authenticator.ts b/octorun/src/authenticator.ts index c30816126..aa43e6acc 100644 --- a/octorun/src/authenticator.ts +++ b/octorun/src/authenticator.ts @@ -1,12 +1,13 @@ //const octokit = require('@octokit/rest') import * as GitHub from '@octokit/rest'; +import { configuration } from './configuration'; export class Authenticator { private github: GitHub; - constructor(){ + constructor() { //Listed defaults from https://github.com/octokit/rest.js#options @@ -14,21 +15,27 @@ export class Authenticator { timeout: 0, // 0 means no request timeout requestMedia: 'application/vnd.github.v3+json', headers: { - 'user-agent': 'octokit/rest.js v1.2.3' // v1.2.3 will be current version + 'user-agent': 'octokit/rest.js v1.2.3' // v1.2.3 will be current version }, - + // change for custom GitHub Enterprise URL host: 'api.github.com', pathPrefix: '', protocol: 'https', port: 443, - + // Node only: advanced request options can be passed as http(s) agent //agent: undefined - }) + }) } - public authenticate() { + public async createAndDeleteExistingApplicationAuthorization() { + const authParams: GitHub.AuthorizationGetOrCreateAuthorizationForAppParams = { + client_id: configuration.ClientId, + client_secret: configuration.ClientSecret, + scopes: ["user", "repo", "gist", "write:public_key"] + }; + await this.github.authorization.getOrCreateAuthorizationForApp(authParams); } } diff --git a/octorun/src/bin/app-login.ts b/octorun/src/bin/app-login.ts index 5022eebd3..a5ea8f3bf 100644 --- a/octorun/src/bin/app-login.ts +++ b/octorun/src/bin/app-login.ts @@ -16,15 +16,15 @@ export class Write { public initialize() { this.program .version(this.package.version) + .option('-l, --login') + .option('-t, --twoFactor') .parse(process.argv); - if (this.program.message != null) { + if (this.program.login) { - // if (typeof this.program.message !== 'string') { - // this.writer.write(); - // } else { - // this.writer.write(this.program.message); - // } + process.exit(); + } + else if (this.program.twoFactor) { process.exit(); } diff --git a/octorun/src/bin/app.ts b/octorun/src/bin/app.ts index 53feb85a4..5bc468e57 100644 --- a/octorun/src/bin/app.ts +++ b/octorun/src/bin/app.ts @@ -1,3 +1,5 @@ +//require('dotenv').config(); + import * as commander from 'commander'; export class App { @@ -13,6 +15,7 @@ export class App { public initialize() { this.program .version(this.package.version) + .command('login [-h|-2fa]', 'Authenticate') .command('write [message]', 'say hello!') .parse(process.argv); } diff --git a/octorun/src/configuration.ts b/octorun/src/configuration.ts new file mode 100644 index 000000000..b72e19aed --- /dev/null +++ b/octorun/src/configuration.ts @@ -0,0 +1,6 @@ +const configuration = { + ClientId: process.env.OCTOKIT_CLIENT_ID, + ClientSecret: process.env.OCTOKIT_CLIENT_SECRET, +}; + +export { configuration }; \ No newline at end of file diff --git a/octorun/tsconfig.json b/octorun/tsconfig.json index 7706353b9..021d9fb8a 100644 --- a/octorun/tsconfig.json +++ b/octorun/tsconfig.json @@ -1,21 +1,22 @@ { - "compileOnSave": false, - "compilerOptions": { - "target": "es6", - "declaration": true, - "module": "commonjs", - "moduleResolution": "node", - "noImplicitAny": true, - "outDir": "./dist", - "preserveConstEnums": true, - "removeComments": true - }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules", - "!node_modules/@types", - "test/**/*-spec.ts" - ] + "compileOnSave": false, + "compilerOptions": { + "target": "es3", + "declaration": true, + "module": "commonjs", + "moduleResolution": "node", + "noImplicitAny": true, + "outDir": "./dist", + "preserveConstEnums": true, + "removeComments": true, + "lib":["es2015"] + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "!node_modules/@types", + "test/**/*-spec.ts" + ] } From 67220c4fc63a09e19bc7ad3bb7f9319b37322a47 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 28 Feb 2018 10:20:06 -0500 Subject: [PATCH 0192/1008] Changing package octokit/rest to a modified github@9.3.1 --- octorun/dist/authenticator.d.ts | 2 +- octorun/dist/authenticator.js | 8 +++---- octorun/dist/bin/app-login.js | 42 +-------------------------------- octorun/package.json | 4 ++-- octorun/src/authenticator.ts | 6 ++--- octorun/src/bin/app-login.ts | 2 ++ 6 files changed, 12 insertions(+), 52 deletions(-) diff --git a/octorun/dist/authenticator.d.ts b/octorun/dist/authenticator.d.ts index ba36c1983..cc6697a38 100644 --- a/octorun/dist/authenticator.d.ts +++ b/octorun/dist/authenticator.d.ts @@ -1,5 +1,5 @@ export declare class Authenticator { private github; constructor(); - createAndDeleteExistingApplicationAuthorization(input?: string): Promise; + createAndDeleteExistingApplicationAuthorization(): Promise; } diff --git a/octorun/dist/authenticator.js b/octorun/dist/authenticator.js index 38d60518c..fd2d27f27 100644 --- a/octorun/dist/authenticator.js +++ b/octorun/dist/authenticator.js @@ -35,23 +35,21 @@ var __generator = (this && this.__generator) || function (thisArg, body) { } }; exports.__esModule = true; -var GitHub = require("@octokit/rest"); +var GitHub = require("github"); var configuration_1 = require("./configuration"); var Authenticator = (function () { function Authenticator() { this.github = new GitHub({ timeout: 0, - requestMedia: 'application/vnd.github.v3+json', headers: { 'user-agent': 'octokit/rest.js v1.2.3' }, host: 'api.github.com', pathPrefix: '', - protocol: 'https', - port: 443 + protocol: 'https' }); } - Authenticator.prototype.createAndDeleteExistingApplicationAuthorization = function (input) { + Authenticator.prototype.createAndDeleteExistingApplicationAuthorization = function () { return __awaiter(this, void 0, void 0, function () { var authParams; return __generator(this, function (_a) { diff --git a/octorun/dist/bin/app-login.js b/octorun/dist/bin/app-login.js index afdf9fe8c..4bfbefe90 100644 --- a/octorun/dist/bin/app-login.js +++ b/octorun/dist/bin/app-login.js @@ -1,39 +1,4 @@ "use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [0, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; exports.__esModule = true; var commander = require("commander"); var authenticator_1 = require("../authenticator"); @@ -44,18 +9,13 @@ var Write = (function () { this.authenticator = new authenticator_1.Authenticator(); } Write.prototype.initialize = function () { - var _this = this; this.program .version(this.package.version) .option('-l, --login') .option('-t, --twoFactor') .parse(process.argv); if (this.program.login) { - var blah = function () { return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2]; - }); - }); }; + this.authenticator.createAndDeleteExistingApplicationAuthorization(); process.exit(); } else if (this.program.twoFactor) { diff --git a/octorun/package.json b/octorun/package.json index c8dac5670..4c658c7c7 100644 --- a/octorun/package.json +++ b/octorun/package.json @@ -39,8 +39,8 @@ "typescript": "^2.2.1" }, "dependencies": { - "@octokit/rest": "^14.0.9", "commander": "^2.9.0", - "dotenv": "^5.0.1" + "dotenv": "^5.0.1", + "github": "git+https://github.com/StanleyGoldman/rest.js.git#gfu" } } diff --git a/octorun/src/authenticator.ts b/octorun/src/authenticator.ts index aa43e6acc..290241364 100644 --- a/octorun/src/authenticator.ts +++ b/octorun/src/authenticator.ts @@ -1,6 +1,6 @@ //const octokit = require('@octokit/rest') -import * as GitHub from '@octokit/rest'; +import * as GitHub from 'github'; import { configuration } from './configuration'; export class Authenticator { @@ -13,7 +13,7 @@ export class Authenticator { this.github = new GitHub({ timeout: 0, // 0 means no request timeout - requestMedia: 'application/vnd.github.v3+json', + //requestMedia: 'application/vnd.github.v3+json', headers: { 'user-agent': 'octokit/rest.js v1.2.3' // v1.2.3 will be current version }, @@ -22,7 +22,7 @@ export class Authenticator { host: 'api.github.com', pathPrefix: '', protocol: 'https', - port: 443, + //port: 443, // Node only: advanced request options can be passed as http(s) agent //agent: undefined diff --git a/octorun/src/bin/app-login.ts b/octorun/src/bin/app-login.ts index a5ea8f3bf..d216709fd 100644 --- a/octorun/src/bin/app-login.ts +++ b/octorun/src/bin/app-login.ts @@ -22,6 +22,8 @@ export class Write { if (this.program.login) { + this.authenticator.createAndDeleteExistingApplicationAuthorization() + process.exit(); } else if (this.program.twoFactor) { From 5a6e3aeee594ad857e10d017875a286887ac5dbd Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 28 Feb 2018 15:42:00 -0500 Subject: [PATCH 0193/1008] Changing to a modified @octokit/rest compiled for es3 --- octorun/dist/authenticator.js | 6 +- octorun/package.json | 2 +- octorun/src/authenticator.ts | 8 +- octorun/typings/octokit-rest-es3/index.d.ts | 3476 +++++++++++++++++++ 4 files changed, 3485 insertions(+), 7 deletions(-) create mode 100644 octorun/typings/octokit-rest-es3/index.d.ts diff --git a/octorun/dist/authenticator.js b/octorun/dist/authenticator.js index fd2d27f27..c6698dc32 100644 --- a/octorun/dist/authenticator.js +++ b/octorun/dist/authenticator.js @@ -35,18 +35,20 @@ var __generator = (this && this.__generator) || function (thisArg, body) { } }; exports.__esModule = true; -var GitHub = require("github"); +var GitHub = require("octokit-rest-es3"); var configuration_1 = require("./configuration"); var Authenticator = (function () { function Authenticator() { this.github = new GitHub({ timeout: 0, + requestMedia: 'application/vnd.github.v3+json', headers: { 'user-agent': 'octokit/rest.js v1.2.3' }, host: 'api.github.com', pathPrefix: '', - protocol: 'https' + protocol: 'https', + port: 443 }); } Authenticator.prototype.createAndDeleteExistingApplicationAuthorization = function () { diff --git a/octorun/package.json b/octorun/package.json index 4c658c7c7..19abf98d1 100644 --- a/octorun/package.json +++ b/octorun/package.json @@ -41,6 +41,6 @@ "dependencies": { "commander": "^2.9.0", "dotenv": "^5.0.1", - "github": "git+https://github.com/StanleyGoldman/rest.js.git#gfu" + "octokit-rest-es3": "github:gr2m/octokit-rest-es3" } } diff --git a/octorun/src/authenticator.ts b/octorun/src/authenticator.ts index 290241364..2e47f5109 100644 --- a/octorun/src/authenticator.ts +++ b/octorun/src/authenticator.ts @@ -1,6 +1,6 @@ -//const octokit = require('@octokit/rest') +/// -import * as GitHub from 'github'; +import * as GitHub from 'octokit-rest-es3'; import { configuration } from './configuration'; export class Authenticator { @@ -13,7 +13,7 @@ export class Authenticator { this.github = new GitHub({ timeout: 0, // 0 means no request timeout - //requestMedia: 'application/vnd.github.v3+json', + requestMedia: 'application/vnd.github.v3+json', headers: { 'user-agent': 'octokit/rest.js v1.2.3' // v1.2.3 will be current version }, @@ -22,7 +22,7 @@ export class Authenticator { host: 'api.github.com', pathPrefix: '', protocol: 'https', - //port: 443, + port: 443, // Node only: advanced request options can be passed as http(s) agent //agent: undefined diff --git a/octorun/typings/octokit-rest-es3/index.d.ts b/octorun/typings/octokit-rest-es3/index.d.ts new file mode 100644 index 000000000..693473ddb --- /dev/null +++ b/octorun/typings/octokit-rest-es3/index.d.ts @@ -0,0 +1,3476 @@ +/** + * This declaration file requires TypeScript 2.1 or above. + */ +declare namespace Github { + type json = any + type date = string + + export interface AnyResponse { + /** This is the data you would see in https://developer.github.com/v3/ */ + data: any + + /** Request metadata */ + meta:{ + 'x-ratelimit-limit': string, + 'x-ratelimit-remaining': string, + 'x-ratelimit-reset': string, + 'x-github-request-id': string, + 'x-github-media-type': string, + link: string, + 'last-modified': string, + etag: string, + status: string + } + + [Symbol.iterator](): Iterator + } + + export interface EmptyParams { + } + + export interface Options { + timeout?: number; + host?: string; + pathPrefix?: string; + protocol?: string; + port?: number; + proxy?: string; + ca?: string; + headers?: {[header: string]: any}; + requestMedia?: string; + rejectUnauthorized?: boolean; + family?: number; + } + + export interface AuthBasic { + type: "basic"; + username: string; + password: string; + } + + export interface AuthOAuthToken { + type: "oauth"; + token: string; + } + + export interface AuthOAuthSecret { + type: "oauth"; + key: string; + secret: string; + } + + export interface AuthUserToken { + type: "token"; + token: string; + } + + export interface AuthJWT { + type: "integration"; + token: string; + } + + export type Auth = + | AuthBasic + | AuthOAuthToken + | AuthOAuthSecret + | AuthUserToken + | AuthJWT; + + export type Link = + | { link: string; } + | { meta: { link: string; }; } + | string; + + export interface Callback { + (error: Error | null, result: any): any; + } + + + export type AuthorizationGetParams = + & { + id: string; + }; + export type AuthorizationCreateParams = + & { + scopes?: string[]; + note?: string; + note_url?: string; + client_id?: string; + client_secret?: string; + fingerprint?: string; + }; + export type AuthorizationUpdateParams = + & { + id: string; + scopes?: string[]; + add_scopes?: string[]; + remove_scopes?: string[]; + note?: string; + note_url?: string; + fingerprint?: string; + }; + export type AuthorizationDeleteParams = + & { + id: string; + }; + export type AuthorizationCheckParams = + & { + client_id?: string; + access_token: string; + }; + export type AuthorizationResetParams = + & { + client_id?: string; + access_token: string; + }; + export type AuthorizationRevokeParams = + & { + client_id?: string; + access_token: string; + }; + export type AuthorizationGetGrantsParams = + & { + page?: number; + per_page?: number; + }; + export type AuthorizationGetGrantParams = + & { + id: string; + page?: number; + per_page?: number; + }; + export type AuthorizationDeleteGrantParams = + & { + id: string; + }; + export type AuthorizationGetAllParams = + & { + page?: number; + per_page?: number; + }; + export type AuthorizationGetOrCreateAuthorizationForAppParams = + & { + client_id?: string; + client_secret: string; + scopes?: string[]; + note?: string; + note_url?: string; + fingerprint?: string; + }; + export type AuthorizationGetOrCreateAuthorizationForAppAndFingerprintParams = + & { + client_id?: string; + fingerprint?: string; + client_secret: string; + scopes?: string[]; + note?: string; + note_url?: string; + }; + export type AuthorizationRevokeGrantParams = + & { + client_id?: string; + access_token: string; + }; + export type ActivityGetEventsParams = + & { + page?: number; + per_page?: number; + }; + export type ActivityGetEventsForRepoParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ActivityGetEventsForRepoIssuesParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ActivityGetEventsForRepoNetworkParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ActivityGetEventsForOrgParams = + & { + org: string; + page?: number; + per_page?: number; + }; + export type ActivityGetEventsReceivedParams = + & { + username: string; + page?: number; + per_page?: number; + }; + export type ActivityGetEventsReceivedPublicParams = + & { + username: string; + page?: number; + per_page?: number; + }; + export type ActivityGetEventsForUserParams = + & { + username: string; + page?: number; + per_page?: number; + }; + export type ActivityGetEventsForUserPublicParams = + & { + username: string; + page?: number; + per_page?: number; + }; + export type ActivityGetEventsForUserOrgParams = + & { + username: string; + org: string; + page?: number; + per_page?: number; + }; + export type ActivityGetNotificationsParams = + & { + all?: boolean; + participating?: boolean; + since?: date; + before?: string; + }; + export type ActivityGetNotificationsForUserParams = + & { + owner: string; + repo: string; + all?: boolean; + participating?: boolean; + since?: date; + before?: string; + }; + export type ActivityMarkNotificationsAsReadParams = + & { + last_read_at?: string; + }; + export type ActivityMarkNotificationsAsReadForRepoParams = + & { + owner: string; + repo: string; + last_read_at?: string; + }; + export type ActivityGetNotificationThreadParams = + & { + id: string; + }; + export type ActivityMarkNotificationThreadAsReadParams = + & { + id: string; + }; + export type ActivityCheckNotificationThreadSubscriptionParams = + & { + id: string; + }; + export type ActivitySetNotificationThreadSubscriptionParams = + & { + id: string; + subscribed?: boolean; + ignored?: boolean; + }; + export type ActivityDeleteNotificationThreadSubscriptionParams = + & { + id: string; + }; + export type ActivityGetStargazersForRepoParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ActivityGetStarredReposForUserParams = + & { + username: string; + sort?: "created"|"updated"; + direction?: "asc"|"desc"; + page?: number; + per_page?: number; + }; + export type ActivityGetStarredReposParams = + & { + sort?: "created"|"updated"; + direction?: "asc"|"desc"; + page?: number; + per_page?: number; + }; + export type ActivityCheckStarringRepoParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ActivityStarRepoParams = + & { + owner: string; + repo: string; + }; + export type ActivityUnstarRepoParams = + & { + owner: string; + repo: string; + }; + export type ActivityGetWatchersForRepoParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ActivityGetWatchedReposForUserParams = + & { + username: string; + page?: number; + per_page?: number; + }; + export type ActivityGetWatchedReposParams = + & { + page?: number; + per_page?: number; + }; + export type ActivityGetRepoSubscriptionParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ActivitySetRepoSubscriptionParams = + & { + owner: string; + repo: string; + subscribed?: boolean; + ignored?: boolean; + }; + export type ActivityUnwatchRepoParams = + & { + owner: string; + repo: string; + }; + export type GistsGetParams = + & { + id: string; + }; + export type GistsCreateParams = + & { + files: json; + description?: string; + public: boolean; + }; + export type GistsEditParams = + & { + id: string; + description?: string; + files: json; + content?: string; + filename?: string; + }; + export type GistsStarParams = + & { + id: string; + }; + export type GistsUnstarParams = + & { + id: string; + }; + export type GistsForkParams = + & { + id: string; + }; + export type GistsDeleteParams = + & { + id: string; + }; + export type GistsGetForUserParams = + & { + username: string; + since?: date; + page?: number; + per_page?: number; + }; + export type GistsGetAllParams = + & { + since?: date; + page?: number; + per_page?: number; + }; + export type GistsGetPublicParams = + & { + since?: date; + }; + export type GistsGetStarredParams = + & { + since?: date; + }; + export type GistsGetRevisionParams = + & { + id: string; + sha: string; + }; + export type GistsGetCommitsParams = + & { + id: string; + }; + export type GistsCheckStarParams = + & { + id: string; + }; + export type GistsGetForksParams = + & { + id: string; + page?: number; + per_page?: number; + }; + export type GistsGetCommentsParams = + & { + gist_id: string; + }; + export type GistsGetCommentParams = + & { + gist_id: string; + id: string; + }; + export type GistsCreateCommentParams = + & { + gist_id: string; + body: string; + }; + export type GistsEditCommentParams = + & { + gist_id: string; + id: string; + body: string; + }; + export type GistsDeleteCommentParams = + & { + gist_id: string; + id: string; + }; + export type GitdataGetBlobParams = + & { + owner: string; + repo: string; + sha: string; + page?: number; + per_page?: number; + }; + export type GitdataCreateBlobParams = + & { + owner: string; + repo: string; + content: string; + encoding: string; + }; + export type GitdataGetCommitParams = + & { + owner: string; + repo: string; + sha: string; + }; + export type GitdataCreateCommitParams = + & { + owner: string; + repo: string; + message: string; + tree: string; + parents: string[]; + author?: json; + committer?: json; + }; + export type GitdataGetCommitSignatureVerificationParams = + & { + owner: string; + repo: string; + sha: string; + }; + export type GitdataGetReferenceParams = + & { + owner: string; + repo: string; + ref: string; + }; + export type GitdataGetReferencesParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type GitdataGetTagsParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type GitdataCreateReferenceParams = + & { + owner: string; + repo: string; + ref: string; + sha: string; + }; + export type GitdataUpdateReferenceParams = + & { + owner: string; + repo: string; + ref: string; + sha: string; + force?: boolean; + }; + export type GitdataDeleteReferenceParams = + & { + owner: string; + repo: string; + ref: string; + }; + export type GitdataGetTagParams = + & { + owner: string; + repo: string; + sha: string; + }; + export type GitdataCreateTagParams = + & { + owner: string; + repo: string; + tag: string; + message: string; + object: string; + type: string; + tagger: json; + }; + export type GitdataGetTagSignatureVerificationParams = + & { + owner: string; + repo: string; + sha: string; + }; + export type GitdataGetTreeParams = + & { + owner: string; + repo: string; + sha: string; + recursive?: boolean; + }; + export type GitdataCreateTreeParams = + & { + owner: string; + repo: string; + tree: json; + base_tree?: string; + }; + export type IntegrationsGetInstallationsParams = + & { + page?: number; + per_page?: number; + }; + export type IntegrationsCreateInstallationTokenParams = + & { + installation_id: string; + user_id?: string; + }; + export type IntegrationsGetInstallationRepositoriesParams = + & { + user_id?: string; + }; + export type IntegrationsAddRepoToInstallationParams = + & { + installation_id: string; + repository_id: string; + }; + export type IntegrationsRemoveRepoFromInstallationParams = + & { + installation_id: string; + repository_id: string; + }; + export type AppsGetForSlugParams = + & { + app_slug: string; + }; + export type AppsGetInstallationsParams = + & { + page?: number; + per_page?: number; + }; + export type AppsGetInstallationParams = + & { + installation_id: string; + }; + export type AppsCreateInstallationTokenParams = + & { + installation_id: string; + user_id?: string; + }; + export type AppsGetInstallationRepositoriesParams = + & { + user_id?: string; + }; + export type AppsAddRepoToInstallationParams = + & { + installation_id: string; + repository_id: string; + }; + export type AppsRemoveRepoFromInstallationParams = + & { + installation_id: string; + repository_id: string; + }; + export type AppsGetMarketplaceListingPlansParams = + & { + page?: number; + per_page?: number; + }; + export type AppsGetMarketplaceListingStubbedPlansParams = + & { + page?: number; + per_page?: number; + }; + export type AppsGetMarketplaceListingPlanAccountsParams = + & { + id: string; + page?: number; + per_page?: number; + }; + export type AppsGetMarketplaceListingStubbedPlanAccountsParams = + & { + id: string; + page?: number; + per_page?: number; + }; + export type AppsCheckMarketplaceListingAccountParams = + & { + id: string; + }; + export type AppsCheckMarketplaceListingStubbedAccountParams = + & { + id: string; + }; + export type IssuesGetParams = + & { + owner: string; + repo: string; + number: number; + }; + export type IssuesCreateParams = + & { + owner: string; + repo: string; + title: string; + body?: string; + assignee?: string; + milestone?: number; + labels?: string[]; + assignees?: string[]; + }; + export type IssuesEditParams = + & { + owner: string; + repo: string; + number: number; + title?: string; + body?: string; + assignee?: string; + state?: "open"|"closed"; + milestone?: number; + labels?: string[]; + assignees?: string[]; + }; + export type IssuesLockParams = + & { + owner: string; + repo: string; + number: number; + }; + export type IssuesUnlockParams = + & { + owner: string; + repo: string; + number: number; + }; + export type IssuesGetAllParams = + & { + filter?: "all"|"assigned"|"created"|"mentioned"|"subscribed"; + state?: "open"|"closed"|"all"; + labels?: string; + sort?: "created"|"updated"|"comments"; + direction?: "asc"|"desc"; + since?: date; + page?: number; + per_page?: number; + }; + export type IssuesGetForUserParams = + & { + filter?: "all"|"assigned"|"created"|"mentioned"|"subscribed"; + state?: "open"|"closed"|"all"; + labels?: string; + sort?: "created"|"updated"|"comments"; + direction?: "asc"|"desc"; + since?: date; + page?: number; + per_page?: number; + }; + export type IssuesGetForOrgParams = + & { + org: string; + filter?: "all"|"assigned"|"created"|"mentioned"|"subscribed"; + state?: "open"|"closed"|"all"; + labels?: string; + sort?: "created"|"updated"|"comments"; + direction?: "asc"|"desc"; + since?: date; + page?: number; + per_page?: number; + }; + export type IssuesGetForRepoParams = + & { + owner: string; + repo: string; + milestone?: string; + state?: "open"|"closed"|"all"; + assignee?: string; + creator?: string; + mentioned?: string; + labels?: string; + sort?: "created"|"updated"|"comments"; + direction?: "asc"|"desc"; + since?: date; + page?: number; + per_page?: number; + }; + export type IssuesGetAssigneesParams = + & { + owner: string; + repo: string; + }; + export type IssuesCheckAssigneeParams = + & { + owner: string; + repo: string; + assignee: string; + }; + export type IssuesAddAssigneesToIssueParams = + & { + owner: string; + repo: string; + number: number; + assignees: string[]; + }; + export type IssuesRemoveAssigneesFromIssueParams = + & { + owner: string; + repo: string; + number: number; + body: json; + }; + export type IssuesGetCommentsParams = + & { + owner: string; + repo: string; + number: number; + since?: date; + page?: number; + per_page?: number; + }; + export type IssuesGetCommentsForRepoParams = + & { + owner: string; + repo: string; + sort?: "created"|"updated"; + direction?: "asc"|"desc"; + since?: date; + page?: number; + per_page?: number; + }; + export type IssuesGetCommentParams = + & { + owner: string; + repo: string; + id: string; + }; + export type IssuesCreateCommentParams = + & { + owner: string; + repo: string; + number: number; + body: string; + }; + export type IssuesEditCommentParams = + & { + owner: string; + repo: string; + id: string; + body: string; + }; + export type IssuesDeleteCommentParams = + & { + owner: string; + repo: string; + id: string; + }; + export type IssuesGetEventsParams = + & { + owner: string; + repo: string; + issue_number: number; + page?: number; + per_page?: number; + }; + export type IssuesGetEventsForRepoParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type IssuesGetEventParams = + & { + owner: string; + repo: string; + id: string; + }; + export type IssuesGetLabelsParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type IssuesGetLabelParams = + & { + owner: string; + repo: string; + name: string; + }; + export type IssuesCreateLabelParams = + & { + owner: string; + repo: string; + name: string; + color: string; + }; + export type IssuesUpdateLabelParams = + & { + owner: string; + repo: string; + oldname: string; + name: string; + color: string; + }; + export type IssuesDeleteLabelParams = + & { + owner: string; + repo: string; + name: string; + }; + export type IssuesGetIssueLabelsParams = + & { + owner: string; + repo: string; + number: number; + }; + export type IssuesAddLabelsParams = + & { + owner: string; + repo: string; + number: number; + labels: string[]; + }; + export type IssuesRemoveLabelParams = + & { + owner: string; + repo: string; + number: number; + name: string; + }; + export type IssuesReplaceAllLabelsParams = + & { + owner: string; + repo: string; + number: number; + labels: string[]; + }; + export type IssuesRemoveAllLabelsParams = + & { + owner: string; + repo: string; + number: number; + }; + export type IssuesGetMilestoneLabelsParams = + & { + owner: string; + repo: string; + number: number; + }; + export type IssuesGetMilestonesParams = + & { + owner: string; + repo: string; + state?: "open"|"closed"|"all"; + sort?: "due_on"|"completeness"; + direction?: "asc"|"desc"; + page?: number; + per_page?: number; + }; + export type IssuesGetMilestoneParams = + & { + owner: string; + repo: string; + number: number; + }; + export type IssuesCreateMilestoneParams = + & { + owner: string; + repo: string; + title: string; + state?: "open"|"closed"|"all"; + description?: string; + due_on?: date; + }; + export type IssuesUpdateMilestoneParams = + & { + owner: string; + repo: string; + number: number; + title: string; + state?: "open"|"closed"|"all"; + description?: string; + due_on?: date; + }; + export type IssuesDeleteMilestoneParams = + & { + owner: string; + repo: string; + number: number; + }; + export type IssuesGetEventsTimelineParams = + & { + owner: string; + repo: string; + issue_number: number; + page?: number; + per_page?: number; + }; + export type MigrationsStartMigrationParams = + & { + org: string; + repositories: string[]; + lock_repositories?: boolean; + exclude_attachments?: boolean; + }; + export type MigrationsGetMigrationsParams = + & { + org: string; + page?: number; + per_page?: number; + }; + export type MigrationsGetMigrationStatusParams = + & { + org: string; + id: string; + }; + export type MigrationsGetMigrationArchiveLinkParams = + & { + org: string; + id: string; + }; + export type MigrationsDeleteMigrationArchiveParams = + & { + org: string; + id: string; + }; + export type MigrationsUnlockRepoLockedForMigrationParams = + & { + org: string; + id: string; + repo_name: string; + }; + export type MigrationsStartImportParams = + & { + owner: string; + repo: string; + vcs_url: string; + vcs?: "subversion"|"git"|"mercurial"|"tfvc"; + vcs_username?: string; + vcs_password?: string; + tfvc_project?: string; + }; + export type MigrationsGetImportProgressParams = + & { + owner: string; + repo: string; + }; + export type MigrationsUpdateImportParams = + & { + owner: string; + repo: string; + vcs_username?: string; + vcs_password?: string; + }; + export type MigrationsGetImportCommitAuthorsParams = + & { + owner: string; + repo: string; + since?: string; + }; + export type MigrationsMapImportCommitAuthorParams = + & { + owner: string; + repo: string; + author_id: string; + email?: string; + name?: string; + }; + export type MigrationsSetImportLfsPreferenceParams = + & { + owner: string; + name: string; + use_lfs: string; + }; + export type MigrationsGetLargeImportFilesParams = + & { + owner: string; + name: string; + }; + export type MigrationsCancelImportParams = + & { + owner: string; + repo: string; + }; + export type MiscGetCodeOfConductParams = + & { + key: string; + }; + export type MiscGetRepoCodeOfConductParams = + & { + owner: string; + repo: string; + }; + export type MiscGetGitignoreTemplateParams = + & { + name: string; + }; + export type MiscGetLicenseParams = + & { + license: string; + }; + export type MiscGetRepoLicenseParams = + & { + owner: string; + repo: string; + }; + export type MiscRenderMarkdownParams = + & { + text: string; + mode?: "markdown"|"gfm"; + context?: string; + }; + export type MiscRenderMarkdownRawParams = + & { + data: string; + }; + export type OrgsGetParams = + & { + org: string; + page?: number; + per_page?: number; + }; + export type OrgsUpdateParams = + & { + org: string; + billing_email?: string; + company?: string; + email?: string; + location?: string; + name?: string; + description?: string; + default_repository_permission?: "read"|"write"|"admin"|"none"; + members_can_create_repositories?: boolean; + }; + export type OrgsGetAllParams = + & { + since?: string; + page?: number; + per_page?: number; + }; + export type OrgsGetForUserParams = + & { + username: string; + page?: number; + per_page?: number; + }; + export type OrgsGetMembersParams = + & { + org: string; + filter?: "all"|"2fa_disabled"; + role?: "all"|"admin"|"member"; + page?: number; + per_page?: number; + }; + export type OrgsCheckMembershipParams = + & { + org: string; + username: string; + }; + export type OrgsRemoveMemberParams = + & { + org: string; + username: string; + }; + export type OrgsGetPublicMembersParams = + & { + org: string; + }; + export type OrgsCheckPublicMembershipParams = + & { + org: string; + username: string; + }; + export type OrgsPublicizeMembershipParams = + & { + org: string; + username: string; + }; + export type OrgsConcealMembershipParams = + & { + org: string; + username: string; + }; + export type OrgsGetOrgMembershipParams = + & { + org: string; + username: string; + }; + export type OrgsAddOrgMembershipParams = + & { + org: string; + username: string; + role: "admin"|"member"; + }; + export type OrgsRemoveOrgMembershipParams = + & { + org: string; + username: string; + }; + export type OrgsGetPendingOrgInvitesParams = + & { + org: string; + }; + export type OrgsGetOutsideCollaboratorsParams = + & { + org: string; + filter?: "all"|"2fa_disabled"; + page?: number; + per_page?: number; + }; + export type OrgsRemoveOutsideCollaboratorParams = + & { + org: string; + username: string; + }; + export type OrgsConvertMemberToOutsideCollaboratorParams = + & { + org: string; + username: string; + }; + export type OrgsGetTeamsParams = + & { + org: string; + page?: number; + per_page?: number; + }; + export type OrgsGetTeamParams = + & { + id: string; + }; + export type OrgsCreateTeamParams = + & { + org: string; + name: string; + description?: string; + maintainers?: string[]; + repo_names?: string[]; + privacy?: "secret"|"closed"; + parent_team_id?: string; + }; + export type OrgsEditTeamParams = + & { + id: string; + name: string; + description?: string; + privacy?: "secret"|"closed"; + parent_team_id?: string; + }; + export type OrgsDeleteTeamParams = + & { + id: string; + }; + export type OrgsGetTeamMembersParams = + & { + id: string; + role?: "member"|"maintainer"|"all"; + page?: number; + per_page?: number; + }; + export type OrgsGetChildTeamsParams = + & { + id: string; + page?: number; + per_page?: number; + }; + export type OrgsGetTeamMembershipParams = + & { + id: string; + username: string; + }; + export type OrgsAddTeamMembershipParams = + & { + id: string; + username: string; + role?: "member"|"maintainer"; + }; + export type OrgsRemoveTeamMembershipParams = + & { + id: string; + username: string; + }; + export type OrgsGetTeamReposParams = + & { + id: string; + page?: number; + per_page?: number; + }; + export type OrgsGetPendingTeamInvitesParams = + & { + id: string; + page?: number; + per_page?: number; + }; + export type OrgsCheckTeamRepoParams = + & { + id: string; + owner: string; + repo: string; + }; + export type OrgsAddTeamRepoParams = + & { + id: string; + org: string; + repo: string; + permission?: "pull"|"push"|"admin"; + }; + export type OrgsDeleteTeamRepoParams = + & { + id: string; + owner: string; + repo: string; + }; + export type OrgsGetHooksParams = + & { + org: string; + page?: number; + per_page?: number; + }; + export type OrgsGetHookParams = + & { + org: string; + id: string; + }; + export type OrgsCreateHookParams = + & { + org: string; + name: string; + config: json; + events?: string[]; + active?: boolean; + }; + export type OrgsEditHookParams = + & { + org: string; + id: string; + config: json; + events?: string[]; + active?: boolean; + }; + export type OrgsPingHookParams = + & { + org: string; + id: string; + }; + export type OrgsDeleteHookParams = + & { + org: string; + id: string; + }; + export type OrgsGetBlockedUsersParams = + & { + org: string; + page?: number; + per_page?: number; + }; + export type OrgsCheckBlockedUserParams = + & { + org: string; + username: string; + }; + export type OrgsBlockUserParams = + & { + org: string; + username: string; + }; + export type OrgsUnblockUserParams = + & { + org: string; + username: string; + }; + export type ProjectsGetRepoProjectsParams = + & { + owner: string; + repo: string; + state?: "open"|"closed"|"all"; + }; + export type ProjectsGetOrgProjectsParams = + & { + org: string; + state?: "open"|"closed"|"all"; + }; + export type ProjectsGetProjectParams = + & { + id: string; + }; + export type ProjectsCreateRepoProjectParams = + & { + owner: string; + repo: string; + name: string; + body?: string; + }; + export type ProjectsCreateOrgProjectParams = + & { + org: string; + name: string; + body?: string; + }; + export type ProjectsUpdateProjectParams = + & { + id: string; + name: string; + body?: string; + state?: "open"|"closed"|"all"; + }; + export type ProjectsDeleteProjectParams = + & { + id: string; + }; + export type ProjectsGetProjectCardsParams = + & { + column_id: string; + }; + export type ProjectsGetProjectCardParams = + & { + id: string; + }; + export type ProjectsCreateProjectCardParams = + & { + column_id: string; + note?: string; + content_id?: string; + content_type?: string; + }; + export type ProjectsUpdateProjectCardParams = + & { + id: string; + note?: string; + }; + export type ProjectsDeleteProjectCardParams = + & { + id: string; + }; + export type ProjectsMoveProjectCardParams = + & { + id: string; + position: string; + column_id?: string; + }; + export type ProjectsGetProjectColumnsParams = + & { + project_id: string; + }; + export type ProjectsGetProjectColumnParams = + & { + id: string; + }; + export type ProjectsCreateProjectColumnParams = + & { + project_id: string; + name: string; + }; + export type ProjectsUpdateProjectColumnParams = + & { + id: string; + name: string; + }; + export type ProjectsDeleteProjectColumnParams = + & { + id: string; + }; + export type ProjectsMoveProjectColumnParams = + & { + id: string; + position: string; + }; + export type PullRequestsGetParams = + & { + owner: string; + repo: string; + number: number; + }; + export type PullRequestsCreateParams = + & { + owner: string; + repo: string; + head: string; + base: string; + }; + export type PullRequestsUpdateParams = + & { + owner: string; + repo: string; + number: number; + title?: string; + body?: string; + state?: "open"|"closed"; + base?: string; + maintainer_can_modify?: boolean; + }; + export type PullRequestsMergeParams = + & { + owner: string; + repo: string; + number: number; + commit_title?: string; + commit_message?: string; + sha?: string; + merge_method?: "merge"|"squash"|"rebase"; + }; + export type PullRequestsGetAllParams = + & { + owner: string; + repo: string; + state?: "open"|"closed"|"all"; + head?: string; + base?: string; + sort?: "created"|"updated"|"popularity"|"long-running"; + direction?: "asc"|"desc"; + page?: number; + per_page?: number; + }; + export type PullRequestsCreateFromIssueParams = + & { + owner: string; + repo: string; + issue: number; + head: string; + base: string; + }; + export type PullRequestsGetCommitsParams = + & { + owner: string; + repo: string; + number: number; + page?: number; + per_page?: number; + }; + export type PullRequestsGetFilesParams = + & { + owner: string; + repo: string; + number: number; + page?: number; + per_page?: number; + }; + export type PullRequestsCheckMergedParams = + & { + owner: string; + repo: string; + number: number; + page?: number; + per_page?: number; + }; + export type PullRequestsGetReviewsParams = + & { + owner: string; + repo: string; + number: number; + page?: number; + per_page?: number; + }; + export type PullRequestsGetReviewParams = + & { + owner: string; + repo: string; + number: number; + id: string; + }; + export type PullRequestsDeletePendingReviewParams = + & { + owner: string; + repo: string; + number: number; + id: string; + }; + export type PullRequestsGetReviewCommentsParams = + & { + owner: string; + repo: string; + number: number; + id: string; + page?: number; + per_page?: number; + }; + export type PullRequestsCreateReviewParams = + & { + owner: string; + repo: string; + number: number; + commit_id?: string; + body?: string; + event?: "APPROVE"|"REQUEST_CHANGES"|"COMMENT"|"PENDING"; + comments?: string[]; + }; + export type PullRequestsSubmitReviewParams = + & { + owner: string; + repo: string; + number: number; + id: string; + body?: string; + event?: "APPROVE"|"REQUEST_CHANGES"|"COMMENT"|"PENDING"; + }; + export type PullRequestsDismissReviewParams = + & { + owner: string; + repo: string; + number: number; + id: string; + message?: string; + page?: number; + per_page?: number; + }; + export type PullRequestsGetCommentsParams = + & { + owner: string; + repo: string; + number: number; + page?: number; + per_page?: number; + }; + export type PullRequestsGetCommentsForRepoParams = + & { + owner: string; + repo: string; + sort?: "created"|"updated"; + direction?: "asc"|"desc"; + since?: date; + page?: number; + per_page?: number; + }; + export type PullRequestsGetCommentParams = + & { + owner: string; + repo: string; + id: string; + }; + export type PullRequestsCreateCommentParams = + & { + owner: string; + repo: string; + number: number; + body: string; + }; + export type PullRequestsCreateCommentReplyParams = + & { + owner: string; + repo: string; + number: number; + body: string; + in_reply_to: number; + }; + export type PullRequestsEditCommentParams = + & { + owner: string; + repo: string; + id: string; + body: string; + }; + export type PullRequestsDeleteCommentParams = + & { + owner: string; + repo: string; + id: string; + }; + export type PullRequestsGetReviewRequestsParams = + & { + owner: string; + repo: string; + number: number; + page?: number; + per_page?: number; + }; + export type PullRequestsCreateReviewRequestParams = + & { + owner: string; + repo: string; + number: number; + reviewers?: string[]; + team_reviewers?: string[]; + }; + export type PullRequestsDeleteReviewRequestParams = + & { + owner: string; + repo: string; + number: number; + reviewers?: string[]; + team_reviewers?: string[]; + }; + export type ReactionsDeleteParams = + & { + id: string; + }; + export type ReactionsGetForCommitCommentParams = + & { + owner: string; + repo: string; + id: string; + content?: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; + }; + export type ReactionsCreateForCommitCommentParams = + & { + owner: string; + repo: string; + id: string; + content: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; + }; + export type ReactionsGetForIssueParams = + & { + owner: string; + repo: string; + number: number; + content?: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; + }; + export type ReactionsCreateForIssueParams = + & { + owner: string; + repo: string; + number: number; + content: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; + }; + export type ReactionsGetForIssueCommentParams = + & { + owner: string; + repo: string; + id: string; + content?: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; + }; + export type ReactionsCreateForIssueCommentParams = + & { + owner: string; + repo: string; + id: string; + content: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; + }; + export type ReactionsGetForPullRequestReviewCommentParams = + & { + owner: string; + repo: string; + id: string; + content?: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; + }; + export type ReactionsCreateForPullRequestReviewCommentParams = + & { + owner: string; + repo: string; + id: string; + content: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; + }; + export type ReposCreateParams = + & { + name: string; + description?: string; + homepage?: string; + private?: boolean; + has_issues?: boolean; + has_projects?: boolean; + has_wiki?: boolean; + team_id?: number; + auto_init?: boolean; + gitignore_template?: string; + license_template?: string; + allow_squash_merge?: boolean; + allow_merge_commit?: boolean; + allow_rebase_merge?: boolean; + }; + export type ReposGetParams = + & { + owner: string; + repo: string; + }; + export type ReposEditParams = + & { + owner: string; + repo: string; + name: string; + description?: string; + homepage?: string; + private?: boolean; + has_issues?: boolean; + has_projects?: boolean; + has_wiki?: boolean; + default_branch?: string; + allow_squash_merge?: boolean; + allow_merge_commit?: boolean; + allow_rebase_merge?: boolean; + }; + export type ReposDeleteParams = + & { + owner: string; + repo: string; + }; + export type ReposForkParams = + & { + owner: string; + repo: string; + organization?: string; + }; + export type ReposMergeParams = + & { + owner: string; + repo: string; + base: string; + head: string; + commit_message?: string; + }; + export type ReposGetAllParams = + & { + visibility?: "all"|"public"|"private"; + affiliation?: string; + type?: "all"|"owner"|"public"|"private"|"member"; + sort?: "created"|"updated"|"pushed"|"full_name"; + direction?: "asc"|"desc"; + page?: number; + per_page?: number; + }; + export type ReposGetForUserParams = + & { + username: string; + type?: "all"|"owner"|"member"; + sort?: "created"|"updated"|"pushed"|"full_name"; + direction?: "asc"|"desc"; + page?: number; + per_page?: number; + }; + export type ReposGetForOrgParams = + & { + org: string; + type?: "all"|"public"|"private"|"forks"|"sources"|"member"; + page?: number; + per_page?: number; + }; + export type ReposGetPublicParams = + & { + since?: string; + page?: number; + per_page?: number; + }; + export type ReposCreateForOrgParams = + & { + org: string; + name: string; + description?: string; + homepage?: string; + private?: boolean; + has_issues?: boolean; + has_projects?: boolean; + has_wiki?: boolean; + team_id?: number; + auto_init?: boolean; + gitignore_template?: string; + license_template?: string; + allow_squash_merge?: boolean; + allow_merge_commit?: boolean; + allow_rebase_merge?: boolean; + }; + export type ReposGetByIdParams = + & { + id: string; + }; + export type ReposGetTopicsParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposReplaceTopicsParams = + & { + owner: string; + repo: string; + names: string[]; + }; + export type ReposGetContributorsParams = + & { + owner: string; + repo: string; + anon?: boolean; + page?: number; + per_page?: number; + }; + export type ReposGetLanguagesParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetTeamsParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetTagsParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetBranchesParams = + & { + owner: string; + repo: string; + protected?: boolean; + page?: number; + per_page?: number; + }; + export type ReposGetBranchParams = + & { + owner: string; + repo: string; + branch: string; + page?: number; + per_page?: number; + }; + export type ReposGetBranchProtectionParams = + & { + owner: string; + repo: string; + branch: string; + page?: number; + per_page?: number; + }; + export type ReposUpdateBranchProtectionParams = + & { + owner: string; + repo: string; + branch: string; + required_status_checks: json; + required_pull_request_reviews: json; + dismissal_restrictions?: json; + restrictions: json; + enforce_admins: boolean; + page?: number; + per_page?: number; + }; + export type ReposRemoveBranchProtectionParams = + & { + owner: string; + repo: string; + branch: string; + }; + export type ReposGetProtectedBranchRequiredStatusChecksParams = + & { + owner: string; + repo: string; + branch: string; + page?: number; + per_page?: number; + }; + export type ReposUpdateProtectedBranchRequiredStatusChecksParams = + & { + owner: string; + repo: string; + branch: string; + strict?: boolean; + contexts?: string[]; + }; + export type ReposRemoveProtectedBranchRequiredStatusChecksParams = + & { + owner: string; + repo: string; + branch: string; + }; + export type ReposGetProtectedBranchRequiredStatusChecksContextsParams = + & { + owner: string; + repo: string; + branch: string; + page?: number; + per_page?: number; + }; + export type ReposReplaceProtectedBranchRequiredStatusChecksContextsParams = + & { + owner: string; + repo: string; + branch: string; + contexts: string[]; + }; + export type ReposAddProtectedBranchRequiredStatusChecksContextsParams = + & { + owner: string; + repo: string; + branch: string; + contexts: string[]; + }; + export type ReposRemoveProtectedBranchRequiredStatusChecksContextsParams = + & { + owner: string; + repo: string; + branch: string; + contexts: string[]; + }; + export type ReposGetProtectedBranchPullRequestReviewEnforcementParams = + & { + owner: string; + repo: string; + branch: string; + page?: number; + per_page?: number; + }; + export type ReposUpdateProtectedBranchPullRequestReviewEnforcementParams = + & { + owner: string; + repo: string; + branch: string; + dismissal_restrictions?: json; + dismiss_stale_reviews?: boolean; + require_code_owner_reviews?: boolean; + }; + export type ReposRemoveProtectedBranchPullRequestReviewEnforcementParams = + & { + owner: string; + repo: string; + branch: string; + }; + export type ReposGetProtectedBranchAdminEnforcementParams = + & { + owner: string; + repo: string; + branch: string; + page?: number; + per_page?: number; + }; + export type ReposAddProtectedBranchAdminEnforcementParams = + & { + owner: string; + repo: string; + branch: string; + page?: number; + per_page?: number; + }; + export type ReposRemoveProtectedBranchAdminEnforcementParams = + & { + owner: string; + repo: string; + branch: string; + }; + export type ReposGetProtectedBranchRestrictionsParams = + & { + owner: string; + repo: string; + branch: string; + page?: number; + per_page?: number; + }; + export type ReposRemoveProtectedBranchRestrictionsParams = + & { + owner: string; + repo: string; + branch: string; + }; + export type ReposGetProtectedBranchTeamRestrictionsParams = + & { + owner: string; + repo: string; + branch: string; + page?: number; + per_page?: number; + }; + export type ReposReplaceProtectedBranchTeamRestrictionsParams = + & { + owner: string; + repo: string; + branch: string; + teams: string[]; + }; + export type ReposAddProtectedBranchTeamRestrictionsParams = + & { + owner: string; + repo: string; + branch: string; + teams: string[]; + }; + export type ReposRemoveProtectedBranchTeamRestrictionsParams = + & { + owner: string; + repo: string; + branch: string; + teams: string[]; + }; + export type ReposGetProtectedBranchUserRestrictionsParams = + & { + owner: string; + repo: string; + branch: string; + page?: number; + per_page?: number; + }; + export type ReposReplaceProtectedBranchUserRestrictionsParams = + & { + owner: string; + repo: string; + branch: string; + users: string[]; + }; + export type ReposAddProtectedBranchUserRestrictionsParams = + & { + owner: string; + repo: string; + branch: string; + users: string[]; + }; + export type ReposRemoveProtectedBranchUserRestrictionsParams = + & { + owner: string; + repo: string; + branch: string; + users: string[]; + }; + export type ReposGetCollaboratorsParams = + & { + owner: string; + repo: string; + affiliation?: "outside"|"all"|"direct"; + page?: number; + per_page?: number; + }; + export type ReposCheckCollaboratorParams = + & { + owner: string; + repo: string; + username: string; + }; + export type ReposReviewUserPermissionLevelParams = + & { + owner: string; + repo: string; + username: string; + }; + export type ReposAddCollaboratorParams = + & { + owner: string; + repo: string; + username: string; + permission?: "pull"|"push"|"admin"; + }; + export type ReposRemoveCollaboratorParams = + & { + owner: string; + repo: string; + username: string; + }; + export type ReposGetAllCommitCommentsParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetCommitCommentsParams = + & { + owner: string; + repo: string; + ref: string; + page?: number; + per_page?: number; + }; + export type ReposCreateCommitCommentParams = + & { + owner: string; + repo: string; + sha: string; + body: string; + path?: string; + position?: number; + }; + export type ReposGetCommitCommentParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposUpdateCommitCommentParams = + & { + owner: string; + repo: string; + id: string; + body: string; + }; + export type ReposDeleteCommitCommentParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposGetCommunityProfileMetricsParams = + & { + owner: string; + name: string; + }; + export type ReposGetCommitsParams = + & { + owner: string; + repo: string; + sha?: string; + path?: string; + author?: string; + since?: date; + until?: date; + page?: number; + per_page?: number; + }; + export type ReposGetCommitParams = + & { + owner: string; + repo: string; + sha: string; + }; + export type ReposGetShaOfCommitRefParams = + & { + owner: string; + repo: string; + ref: string; + }; + export type ReposCompareCommitsParams = + & { + owner: string; + repo: string; + base: string; + head: string; + }; + export type ReposGetReadmeParams = + & { + owner: string; + repo: string; + ref?: string; + }; + export type ReposGetContentParams = + & { + owner: string; + repo: string; + path: string; + ref?: string; + }; + export type ReposCreateFileParams = + & { + owner: string; + repo: string; + path: string; + message: string; + content: string; + branch?: string; + committer?: json; + author?: json; + }; + export type ReposUpdateFileParams = + & { + owner: string; + repo: string; + path: string; + message: string; + content: string; + sha: string; + branch?: string; + committer?: json; + author?: json; + }; + export type ReposDeleteFileParams = + & { + owner: string; + repo: string; + path: string; + message: string; + sha: string; + branch?: string; + committer?: json; + author?: json; + }; + export type ReposGetArchiveLinkParams = + & { + owner: string; + repo: string; + archive_format: "tarball"|"zipball"; + ref?: string; + }; + export type ReposGetDeployKeysParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetDeployKeyParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposAddDeployKeyParams = + & { + owner: string; + repo: string; + title: string; + key: string; + read_only?: boolean; + }; + export type ReposDeleteDeployKeyParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposGetDeploymentsParams = + & { + owner: string; + repo: string; + sha?: string; + ref?: string; + task?: string; + environment?: string; + page?: number; + per_page?: number; + }; + export type ReposGetDeploymentParams = + & { + owner: string; + repo: string; + deployment_id: string; + }; + export type ReposCreateDeploymentParams = + & { + owner: string; + repo: string; + ref: string; + task?: string; + auto_merge?: boolean; + required_contexts?: string[]; + payload?: string; + environment?: string; + description?: string; + transient_environment?: boolean; + production_environment?: boolean; + }; + export type ReposGetDeploymentStatusesParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposGetDeploymentStatusParams = + & { + owner: string; + repo: string; + id: string; + status_id: string; + }; + export type ReposCreateDeploymentStatusParams = + & { + owner: string; + repo: string; + id: string; + state?: string; + target_url?: string; + log_url?: string; + description?: string; + environment_url?: string; + auto_inactive?: boolean; + }; + export type ReposGetDownloadsParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetDownloadParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposDeleteDownloadParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposGetForksParams = + & { + owner: string; + repo: string; + sort?: "newest"|"oldest"|"stargazers"; + page?: number; + per_page?: number; + }; + export type ReposGetInvitesParams = + & { + owner: string; + repo: string; + }; + export type ReposDeleteInviteParams = + & { + owner: string; + repo: string; + invitation_id: string; + }; + export type ReposUpdateInviteParams = + & { + owner: string; + repo: string; + invitation_id: string; + permissions?: "read"|"write"|"admin"; + }; + export type ReposGetPagesParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposRequestPageBuildParams = + & { + owner: string; + repo: string; + }; + export type ReposGetPagesBuildsParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetLatestPagesBuildParams = + & { + owner: string; + repo: string; + }; + export type ReposGetPagesBuildParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposGetReleasesParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetReleaseParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposGetLatestReleaseParams = + & { + owner: string; + repo: string; + }; + export type ReposGetReleaseByTagParams = + & { + owner: string; + repo: string; + tag: string; + }; + export type ReposCreateReleaseParams = + & { + owner: string; + repo: string; + tag_name: string; + target_commitish?: string; + name?: string; + body?: string; + draft?: boolean; + prerelease?: boolean; + }; + export type ReposEditReleaseParams = + & { + owner: string; + repo: string; + id: string; + tag_name: string; + target_commitish?: string; + name?: string; + body?: string; + draft?: boolean; + prerelease?: boolean; + }; + export type ReposDeleteReleaseParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposGetAssetsParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposUploadAssetParams = + & { + url: string; + file: string | object; + contentType: string; + contentLength: number; + name: string; + label?: string; + }; + export type ReposGetAssetParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposEditAssetParams = + & { + owner: string; + repo: string; + id: string; + name: string; + label?: string; + }; + export type ReposDeleteAssetParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposGetStatsContributorsParams = + & { + owner: string; + repo: string; + }; + export type ReposGetStatsCommitActivityParams = + & { + owner: string; + repo: string; + }; + export type ReposGetStatsCodeFrequencyParams = + & { + owner: string; + repo: string; + }; + export type ReposGetStatsParticipationParams = + & { + owner: string; + repo: string; + }; + export type ReposGetStatsPunchCardParams = + & { + owner: string; + repo: string; + }; + export type ReposCreateStatusParams = + & { + owner: string; + repo: string; + sha: string; + state: "pending"|"success"|"error"|"failure"; + target_url?: string; + description?: string; + context?: string; + }; + export type ReposGetStatusesParams = + & { + owner: string; + repo: string; + ref: string; + page?: number; + per_page?: number; + }; + export type ReposGetCombinedStatusForRefParams = + & { + owner: string; + repo: string; + ref: string; + page?: number; + per_page?: number; + }; + export type ReposGetReferrersParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetPathsParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetViewsParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetClonesParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetHooksParams = + & { + owner: string; + repo: string; + page?: number; + per_page?: number; + }; + export type ReposGetHookParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposCreateHookParams = + & { + owner: string; + repo: string; + name: string; + config: json; + events?: string[]; + active?: boolean; + }; + export type ReposEditHookParams = + & { + owner: string; + repo: string; + id: string; + name: string; + config: json; + events?: string[]; + add_events?: string[]; + remove_events?: string[]; + active?: boolean; + }; + export type ReposTestHookParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposPingHookParams = + & { + owner: string; + repo: string; + id: string; + }; + export type ReposDeleteHookParams = + & { + owner: string; + repo: string; + id: string; + }; + export type SearchReposParams = + & { + q: string; + sort?: "stars"|"forks"|"updated"; + order?: "asc"|"desc"; + page?: number; + per_page?: number; + }; + export type SearchCodeParams = + & { + q: string; + sort?: "indexed"; + order?: "asc"|"desc"; + page?: number; + per_page?: number; + }; + export type SearchCommitsParams = + & { + q: string; + sort?: "author-date"|"committer-date"; + order?: "asc"|"desc"; + page?: number; + per_page?: number; + }; + export type SearchIssuesParams = + & { + q: string; + sort?: "comments"|"created"|"updated"; + order?: "asc"|"desc"; + page?: number; + per_page?: number; + }; + export type SearchUsersParams = + & { + q: string; + sort?: "followers"|"repositories"|"joined"; + order?: "asc"|"desc"; + page?: number; + per_page?: number; + }; + export type SearchEmailParams = + & { + email: string; + }; + export type UsersUpdateParams = + & { + name?: string; + email?: string; + blog?: string; + company?: string; + location?: string; + hireable?: boolean; + bio?: string; + }; + export type UsersPromoteParams = + & { + username: string; + }; + export type UsersDemoteParams = + & { + username: string; + }; + export type UsersSuspendParams = + & { + username: string; + }; + export type UsersUnsuspendParams = + & { + username: string; + }; + export type UsersGetForUserParams = + & { + username: string; + }; + export type UsersGetByIdParams = + & { + id: string; + }; + export type UsersGetAllParams = + & { + since?: number; + }; + export type UsersGetOrgsParams = + & { + page?: number; + per_page?: number; + }; + export type UsersGetOrgMembershipsParams = + & { + state?: "active"|"pending"; + }; + export type UsersGetOrgMembershipParams = + & { + org: string; + }; + export type UsersEditOrgMembershipParams = + & { + org: string; + state: "active"; + }; + export type UsersGetTeamsParams = + & { + page?: number; + per_page?: number; + }; + export type UsersGetEmailsParams = + & { + page?: number; + per_page?: number; + }; + export type UsersGetPublicEmailsParams = + & { + page?: number; + per_page?: number; + }; + export type UsersAddEmailsParams = + & { + emails: string[]; + }; + export type UsersDeleteEmailsParams = + & { + emails: string[]; + }; + export type UsersGetFollowersForUserParams = + & { + username: string; + page?: number; + per_page?: number; + }; + export type UsersGetFollowersParams = + & { + page?: number; + per_page?: number; + }; + export type UsersGetFollowingForUserParams = + & { + username: string; + page?: number; + per_page?: number; + }; + export type UsersGetFollowingParams = + & { + page?: number; + per_page?: number; + }; + export type UsersCheckFollowingParams = + & { + username: string; + }; + export type UsersCheckIfOneFollowersOtherParams = + & { + username: string; + target_user: string; + }; + export type UsersFollowUserParams = + & { + username: string; + }; + export type UsersUnfollowUserParams = + & { + username: string; + }; + export type UsersGetKeysForUserParams = + & { + username: string; + page?: number; + per_page?: number; + }; + export type UsersGetKeysParams = + & { + page?: number; + per_page?: number; + }; + export type UsersGetKeyParams = + & { + id: string; + }; + export type UsersCreateKeyParams = + & { + title: string; + key: string; + }; + export type UsersDeleteKeyParams = + & { + id: string; + }; + export type UsersGetGpgKeysForUserParams = + & { + username: string; + page?: number; + per_page?: number; + }; + export type UsersGetGpgKeysParams = + & { + page?: number; + per_page?: number; + }; + export type UsersGetGpgKeyParams = + & { + id: string; + }; + export type UsersCreateGpgKeyParams = + & { + armored_public_key: string; + }; + export type UsersDeleteGpgKeyParams = + & { + id: string; + }; + export type UsersCheckBlockedUserParams = + & { + username: string; + }; + export type UsersBlockUserParams = + & { + username: string; + }; + export type UsersUnblockUserParams = + & { + username: string; + }; + export type UsersAcceptRepoInviteParams = + & { + invitation_id: string; + }; + export type UsersDeclineRepoInviteParams = + & { + invitation_id: string; + }; + export type UsersGetInstallationsParams = + & { + page?: number; + per_page?: number; + }; + export type UsersGetInstallationReposParams = + & { + installation_id: string; + page?: number; + per_page?: number; + }; + export type UsersAddRepoToInstallationParams = + & { + installation_id: string; + repository_id: string; + }; + export type UsersRemoveRepoFromInstallationParams = + & { + installation_id: string; + repository_id: string; + }; + export type UsersGetMarketplacePurchasesParams = + & { + page?: number; + per_page?: number; + }; + export type UsersGetMarketplaceStubbedPurchasesParams = + & { + page?: number; + per_page?: number; + }; + export type EnterpriseStatsParams = + & { + type: "issues"|"hooks"|"milestones"|"orgs"|"comments"|"pages"|"users"|"gists"|"pulls"|"repos"|"all"; + }; + export type EnterpriseUpdateLdapForUserParams = + & { + username: string; + ldap_dn: string; + }; + export type EnterpriseSyncLdapForUserParams = + & { + username: string; + }; + export type EnterpriseUpdateLdapForTeamParams = + & { + team_id: number; + ldap_dn: string; + }; + export type EnterpriseSyncLdapForTeamParams = + & { + team_id: number; + }; + export type EnterpriseGetPreReceiveEnvironmentParams = + & { + id: string; + }; + export type EnterpriseCreatePreReceiveEnvironmentParams = + & { + name: string; + image_url: string; + }; + export type EnterpriseEditPreReceiveEnvironmentParams = + & { + id: string; + name: string; + image_url: string; + }; + export type EnterpriseDeletePreReceiveEnvironmentParams = + & { + id: string; + }; + export type EnterpriseGetPreReceiveEnvironmentDownloadStatusParams = + & { + id: string; + }; + export type EnterpriseTriggerPreReceiveEnvironmentDownloadParams = + & { + id: string; + }; + export type EnterpriseGetPreReceiveHookParams = + & { + id: string; + }; + export type EnterpriseCreatePreReceiveHookParams = + & { + name: string; + script: string; + script_repository: json; + environment: json; + enforcement?: string; + allow_downstream_configuration?: boolean; + }; + export type EnterpriseEditPreReceiveHookParams = + & { + id: string; + hook: json; + }; + export type EnterpriseDeletePreReceiveHookParams = + & { + id: string; + }; + export type EnterpriseQueueIndexingJobParams = + & { + target: string; + }; + export type EnterpriseCreateOrgParams = + & { + login: string; + admin: string; + profile_name?: string; + }; +} + +declare class Github { + constructor(options?: Github.Options); + authenticate(auth: Github.Auth): void; + hasNextPage(link: Github.Link): string | undefined; + hasPreviousPage(link: Github.Link): string | undefined; + hasLastPage(link: Github.Link): string | undefined; + hasFirstPage(link: Github.Link): string | undefined; + + getNextPage(link: Github.Link, callback?: Github.Callback): Promise; + getNextPage(link: Github.Link, headers?: {[header: string]: any}, callback?: Github.Callback): Promise; + + getPreviousPage(link: Github.Link, callback?: Github.Callback): Promise; + getPreviousPage(link: Github.Link, headers?: {[header: string]: any}, callback?: Github.Callback): Promise; + + getLastPage(link: Github.Link, callback?: Github.Callback): Promise; + getLastPage(link: Github.Link, headers?: {[header: string]: any}, callback?: Github.Callback): Promise; + + getFirstPage(link: Github.Link, callback?: Github.Callback): Promise; + getFirstPage(link: Github.Link, headers?: {[header: string]: any}, callback?: Github.Callback): Promise; + + authorization: { + get(params: Github.AuthorizationGetParams, callback?: Github.Callback): Promise; + create(params: Github.AuthorizationCreateParams, callback?: Github.Callback): Promise; + update(params: Github.AuthorizationUpdateParams, callback?: Github.Callback): Promise; + delete(params: Github.AuthorizationDeleteParams, callback?: Github.Callback): Promise; + check(params: Github.AuthorizationCheckParams, callback?: Github.Callback): Promise; + reset(params: Github.AuthorizationResetParams, callback?: Github.Callback): Promise; + revoke(params: Github.AuthorizationRevokeParams, callback?: Github.Callback): Promise; + getGrants(params: Github.AuthorizationGetGrantsParams, callback?: Github.Callback): Promise; + getGrant(params: Github.AuthorizationGetGrantParams, callback?: Github.Callback): Promise; + deleteGrant(params: Github.AuthorizationDeleteGrantParams, callback?: Github.Callback): Promise; + getAll(params: Github.AuthorizationGetAllParams, callback?: Github.Callback): Promise; + getOrCreateAuthorizationForApp(params: Github.AuthorizationGetOrCreateAuthorizationForAppParams, callback?: Github.Callback): Promise; + getOrCreateAuthorizationForAppAndFingerprint(params: Github.AuthorizationGetOrCreateAuthorizationForAppAndFingerprintParams, callback?: Github.Callback): Promise; + revokeGrant(params: Github.AuthorizationRevokeGrantParams, callback?: Github.Callback): Promise; + }; + activity: { + getEvents(params: Github.ActivityGetEventsParams, callback?: Github.Callback): Promise; + getEventsForRepo(params: Github.ActivityGetEventsForRepoParams, callback?: Github.Callback): Promise; + getEventsForRepoIssues(params: Github.ActivityGetEventsForRepoIssuesParams, callback?: Github.Callback): Promise; + getEventsForRepoNetwork(params: Github.ActivityGetEventsForRepoNetworkParams, callback?: Github.Callback): Promise; + getEventsForOrg(params: Github.ActivityGetEventsForOrgParams, callback?: Github.Callback): Promise; + getEventsReceived(params: Github.ActivityGetEventsReceivedParams, callback?: Github.Callback): Promise; + getEventsReceivedPublic(params: Github.ActivityGetEventsReceivedPublicParams, callback?: Github.Callback): Promise; + getEventsForUser(params: Github.ActivityGetEventsForUserParams, callback?: Github.Callback): Promise; + getEventsForUserPublic(params: Github.ActivityGetEventsForUserPublicParams, callback?: Github.Callback): Promise; + getEventsForUserOrg(params: Github.ActivityGetEventsForUserOrgParams, callback?: Github.Callback): Promise; + getFeeds(params: Github.EmptyParams, callback?: Github.Callback): Promise; + getNotifications(params: Github.ActivityGetNotificationsParams, callback?: Github.Callback): Promise; + getNotificationsForUser(params: Github.ActivityGetNotificationsForUserParams, callback?: Github.Callback): Promise; + markNotificationsAsRead(params: Github.ActivityMarkNotificationsAsReadParams, callback?: Github.Callback): Promise; + markNotificationsAsReadForRepo(params: Github.ActivityMarkNotificationsAsReadForRepoParams, callback?: Github.Callback): Promise; + getNotificationThread(params: Github.ActivityGetNotificationThreadParams, callback?: Github.Callback): Promise; + markNotificationThreadAsRead(params: Github.ActivityMarkNotificationThreadAsReadParams, callback?: Github.Callback): Promise; + checkNotificationThreadSubscription(params: Github.ActivityCheckNotificationThreadSubscriptionParams, callback?: Github.Callback): Promise; + setNotificationThreadSubscription(params: Github.ActivitySetNotificationThreadSubscriptionParams, callback?: Github.Callback): Promise; + deleteNotificationThreadSubscription(params: Github.ActivityDeleteNotificationThreadSubscriptionParams, callback?: Github.Callback): Promise; + getStargazersForRepo(params: Github.ActivityGetStargazersForRepoParams, callback?: Github.Callback): Promise; + getStarredReposForUser(params: Github.ActivityGetStarredReposForUserParams, callback?: Github.Callback): Promise; + getStarredRepos(params: Github.ActivityGetStarredReposParams, callback?: Github.Callback): Promise; + checkStarringRepo(params: Github.ActivityCheckStarringRepoParams, callback?: Github.Callback): Promise; + starRepo(params: Github.ActivityStarRepoParams, callback?: Github.Callback): Promise; + unstarRepo(params: Github.ActivityUnstarRepoParams, callback?: Github.Callback): Promise; + getWatchersForRepo(params: Github.ActivityGetWatchersForRepoParams, callback?: Github.Callback): Promise; + getWatchedReposForUser(params: Github.ActivityGetWatchedReposForUserParams, callback?: Github.Callback): Promise; + getWatchedRepos(params: Github.ActivityGetWatchedReposParams, callback?: Github.Callback): Promise; + getRepoSubscription(params: Github.ActivityGetRepoSubscriptionParams, callback?: Github.Callback): Promise; + setRepoSubscription(params: Github.ActivitySetRepoSubscriptionParams, callback?: Github.Callback): Promise; + unwatchRepo(params: Github.ActivityUnwatchRepoParams, callback?: Github.Callback): Promise; + }; + gists: { + get(params: Github.GistsGetParams, callback?: Github.Callback): Promise; + create(params: Github.GistsCreateParams, callback?: Github.Callback): Promise; + edit(params: Github.GistsEditParams, callback?: Github.Callback): Promise; + star(params: Github.GistsStarParams, callback?: Github.Callback): Promise; + unstar(params: Github.GistsUnstarParams, callback?: Github.Callback): Promise; + fork(params: Github.GistsForkParams, callback?: Github.Callback): Promise; + delete(params: Github.GistsDeleteParams, callback?: Github.Callback): Promise; + getForUser(params: Github.GistsGetForUserParams, callback?: Github.Callback): Promise; + getAll(params: Github.GistsGetAllParams, callback?: Github.Callback): Promise; + getPublic(params: Github.GistsGetPublicParams, callback?: Github.Callback): Promise; + getStarred(params: Github.GistsGetStarredParams, callback?: Github.Callback): Promise; + getRevision(params: Github.GistsGetRevisionParams, callback?: Github.Callback): Promise; + getCommits(params: Github.GistsGetCommitsParams, callback?: Github.Callback): Promise; + checkStar(params: Github.GistsCheckStarParams, callback?: Github.Callback): Promise; + getForks(params: Github.GistsGetForksParams, callback?: Github.Callback): Promise; + getComments(params: Github.GistsGetCommentsParams, callback?: Github.Callback): Promise; + getComment(params: Github.GistsGetCommentParams, callback?: Github.Callback): Promise; + createComment(params: Github.GistsCreateCommentParams, callback?: Github.Callback): Promise; + editComment(params: Github.GistsEditCommentParams, callback?: Github.Callback): Promise; + deleteComment(params: Github.GistsDeleteCommentParams, callback?: Github.Callback): Promise; + }; + gitdata: { + getBlob(params: Github.GitdataGetBlobParams, callback?: Github.Callback): Promise; + createBlob(params: Github.GitdataCreateBlobParams, callback?: Github.Callback): Promise; + getCommit(params: Github.GitdataGetCommitParams, callback?: Github.Callback): Promise; + createCommit(params: Github.GitdataCreateCommitParams, callback?: Github.Callback): Promise; + getCommitSignatureVerification(params: Github.GitdataGetCommitSignatureVerificationParams, callback?: Github.Callback): Promise; + getReference(params: Github.GitdataGetReferenceParams, callback?: Github.Callback): Promise; + getReferences(params: Github.GitdataGetReferencesParams, callback?: Github.Callback): Promise; + getTags(params: Github.GitdataGetTagsParams, callback?: Github.Callback): Promise; + createReference(params: Github.GitdataCreateReferenceParams, callback?: Github.Callback): Promise; + updateReference(params: Github.GitdataUpdateReferenceParams, callback?: Github.Callback): Promise; + deleteReference(params: Github.GitdataDeleteReferenceParams, callback?: Github.Callback): Promise; + getTag(params: Github.GitdataGetTagParams, callback?: Github.Callback): Promise; + createTag(params: Github.GitdataCreateTagParams, callback?: Github.Callback): Promise; + getTagSignatureVerification(params: Github.GitdataGetTagSignatureVerificationParams, callback?: Github.Callback): Promise; + getTree(params: Github.GitdataGetTreeParams, callback?: Github.Callback): Promise; + createTree(params: Github.GitdataCreateTreeParams, callback?: Github.Callback): Promise; + }; + integrations: { + getInstallations(params: Github.IntegrationsGetInstallationsParams, callback?: Github.Callback): Promise; + createInstallationToken(params: Github.IntegrationsCreateInstallationTokenParams, callback?: Github.Callback): Promise; + getInstallationRepositories(params: Github.IntegrationsGetInstallationRepositoriesParams, callback?: Github.Callback): Promise; + addRepoToInstallation(params: Github.IntegrationsAddRepoToInstallationParams, callback?: Github.Callback): Promise; + removeRepoFromInstallation(params: Github.IntegrationsRemoveRepoFromInstallationParams, callback?: Github.Callback): Promise; + }; + apps: { + get(params: Github.EmptyParams, callback?: Github.Callback): Promise; + getForSlug(params: Github.AppsGetForSlugParams, callback?: Github.Callback): Promise; + getInstallations(params: Github.AppsGetInstallationsParams, callback?: Github.Callback): Promise; + getInstallation(params: Github.AppsGetInstallationParams, callback?: Github.Callback): Promise; + createInstallationToken(params: Github.AppsCreateInstallationTokenParams, callback?: Github.Callback): Promise; + getInstallationRepositories(params: Github.AppsGetInstallationRepositoriesParams, callback?: Github.Callback): Promise; + addRepoToInstallation(params: Github.AppsAddRepoToInstallationParams, callback?: Github.Callback): Promise; + removeRepoFromInstallation(params: Github.AppsRemoveRepoFromInstallationParams, callback?: Github.Callback): Promise; + getMarketplaceListingPlans(params: Github.AppsGetMarketplaceListingPlansParams, callback?: Github.Callback): Promise; + getMarketplaceListingStubbedPlans(params: Github.AppsGetMarketplaceListingStubbedPlansParams, callback?: Github.Callback): Promise; + getMarketplaceListingPlanAccounts(params: Github.AppsGetMarketplaceListingPlanAccountsParams, callback?: Github.Callback): Promise; + getMarketplaceListingStubbedPlanAccounts(params: Github.AppsGetMarketplaceListingStubbedPlanAccountsParams, callback?: Github.Callback): Promise; + checkMarketplaceListingAccount(params: Github.AppsCheckMarketplaceListingAccountParams, callback?: Github.Callback): Promise; + checkMarketplaceListingStubbedAccount(params: Github.AppsCheckMarketplaceListingStubbedAccountParams, callback?: Github.Callback): Promise; + }; + issues: { + get(params: Github.IssuesGetParams, callback?: Github.Callback): Promise; + create(params: Github.IssuesCreateParams, callback?: Github.Callback): Promise; + edit(params: Github.IssuesEditParams, callback?: Github.Callback): Promise; + lock(params: Github.IssuesLockParams, callback?: Github.Callback): Promise; + unlock(params: Github.IssuesUnlockParams, callback?: Github.Callback): Promise; + getAll(params: Github.IssuesGetAllParams, callback?: Github.Callback): Promise; + getForUser(params: Github.IssuesGetForUserParams, callback?: Github.Callback): Promise; + getForOrg(params: Github.IssuesGetForOrgParams, callback?: Github.Callback): Promise; + getForRepo(params: Github.IssuesGetForRepoParams, callback?: Github.Callback): Promise; + getAssignees(params: Github.IssuesGetAssigneesParams, callback?: Github.Callback): Promise; + checkAssignee(params: Github.IssuesCheckAssigneeParams, callback?: Github.Callback): Promise; + addAssigneesToIssue(params: Github.IssuesAddAssigneesToIssueParams, callback?: Github.Callback): Promise; + removeAssigneesFromIssue(params: Github.IssuesRemoveAssigneesFromIssueParams, callback?: Github.Callback): Promise; + getComments(params: Github.IssuesGetCommentsParams, callback?: Github.Callback): Promise; + getCommentsForRepo(params: Github.IssuesGetCommentsForRepoParams, callback?: Github.Callback): Promise; + getComment(params: Github.IssuesGetCommentParams, callback?: Github.Callback): Promise; + createComment(params: Github.IssuesCreateCommentParams, callback?: Github.Callback): Promise; + editComment(params: Github.IssuesEditCommentParams, callback?: Github.Callback): Promise; + deleteComment(params: Github.IssuesDeleteCommentParams, callback?: Github.Callback): Promise; + getEvents(params: Github.IssuesGetEventsParams, callback?: Github.Callback): Promise; + getEventsForRepo(params: Github.IssuesGetEventsForRepoParams, callback?: Github.Callback): Promise; + getEvent(params: Github.IssuesGetEventParams, callback?: Github.Callback): Promise; + getLabels(params: Github.IssuesGetLabelsParams, callback?: Github.Callback): Promise; + getLabel(params: Github.IssuesGetLabelParams, callback?: Github.Callback): Promise; + createLabel(params: Github.IssuesCreateLabelParams, callback?: Github.Callback): Promise; + updateLabel(params: Github.IssuesUpdateLabelParams, callback?: Github.Callback): Promise; + deleteLabel(params: Github.IssuesDeleteLabelParams, callback?: Github.Callback): Promise; + getIssueLabels(params: Github.IssuesGetIssueLabelsParams, callback?: Github.Callback): Promise; + addLabels(params: Github.IssuesAddLabelsParams, callback?: Github.Callback): Promise; + removeLabel(params: Github.IssuesRemoveLabelParams, callback?: Github.Callback): Promise; + replaceAllLabels(params: Github.IssuesReplaceAllLabelsParams, callback?: Github.Callback): Promise; + removeAllLabels(params: Github.IssuesRemoveAllLabelsParams, callback?: Github.Callback): Promise; + getMilestoneLabels(params: Github.IssuesGetMilestoneLabelsParams, callback?: Github.Callback): Promise; + getMilestones(params: Github.IssuesGetMilestonesParams, callback?: Github.Callback): Promise; + getMilestone(params: Github.IssuesGetMilestoneParams, callback?: Github.Callback): Promise; + createMilestone(params: Github.IssuesCreateMilestoneParams, callback?: Github.Callback): Promise; + updateMilestone(params: Github.IssuesUpdateMilestoneParams, callback?: Github.Callback): Promise; + deleteMilestone(params: Github.IssuesDeleteMilestoneParams, callback?: Github.Callback): Promise; + getEventsTimeline(params: Github.IssuesGetEventsTimelineParams, callback?: Github.Callback): Promise; + }; + migrations: { + startMigration(params: Github.MigrationsStartMigrationParams, callback?: Github.Callback): Promise; + getMigrations(params: Github.MigrationsGetMigrationsParams, callback?: Github.Callback): Promise; + getMigrationStatus(params: Github.MigrationsGetMigrationStatusParams, callback?: Github.Callback): Promise; + getMigrationArchiveLink(params: Github.MigrationsGetMigrationArchiveLinkParams, callback?: Github.Callback): Promise; + deleteMigrationArchive(params: Github.MigrationsDeleteMigrationArchiveParams, callback?: Github.Callback): Promise; + unlockRepoLockedForMigration(params: Github.MigrationsUnlockRepoLockedForMigrationParams, callback?: Github.Callback): Promise; + startImport(params: Github.MigrationsStartImportParams, callback?: Github.Callback): Promise; + getImportProgress(params: Github.MigrationsGetImportProgressParams, callback?: Github.Callback): Promise; + updateImport(params: Github.MigrationsUpdateImportParams, callback?: Github.Callback): Promise; + getImportCommitAuthors(params: Github.MigrationsGetImportCommitAuthorsParams, callback?: Github.Callback): Promise; + mapImportCommitAuthor(params: Github.MigrationsMapImportCommitAuthorParams, callback?: Github.Callback): Promise; + setImportLfsPreference(params: Github.MigrationsSetImportLfsPreferenceParams, callback?: Github.Callback): Promise; + getLargeImportFiles(params: Github.MigrationsGetLargeImportFilesParams, callback?: Github.Callback): Promise; + cancelImport(params: Github.MigrationsCancelImportParams, callback?: Github.Callback): Promise; + }; + misc: { + getCodesOfConduct(params: Github.EmptyParams, callback?: Github.Callback): Promise; + getCodeOfConduct(params: Github.MiscGetCodeOfConductParams, callback?: Github.Callback): Promise; + getRepoCodeOfConduct(params: Github.MiscGetRepoCodeOfConductParams, callback?: Github.Callback): Promise; + getEmojis(params: Github.EmptyParams, callback?: Github.Callback): Promise; + getGitignoreTemplates(params: Github.EmptyParams, callback?: Github.Callback): Promise; + getGitignoreTemplate(params: Github.MiscGetGitignoreTemplateParams, callback?: Github.Callback): Promise; + getLicenses(params: Github.EmptyParams, callback?: Github.Callback): Promise; + getLicense(params: Github.MiscGetLicenseParams, callback?: Github.Callback): Promise; + getRepoLicense(params: Github.MiscGetRepoLicenseParams, callback?: Github.Callback): Promise; + renderMarkdown(params: Github.MiscRenderMarkdownParams, callback?: Github.Callback): Promise; + renderMarkdownRaw(params: Github.MiscRenderMarkdownRawParams, callback?: Github.Callback): Promise; + getMeta(params: Github.EmptyParams, callback?: Github.Callback): Promise; + getRateLimit(params: Github.EmptyParams, callback?: Github.Callback): Promise; + }; + orgs: { + get(params: Github.OrgsGetParams, callback?: Github.Callback): Promise; + update(params: Github.OrgsUpdateParams, callback?: Github.Callback): Promise; + getAll(params: Github.OrgsGetAllParams, callback?: Github.Callback): Promise; + getForUser(params: Github.OrgsGetForUserParams, callback?: Github.Callback): Promise; + getMembers(params: Github.OrgsGetMembersParams, callback?: Github.Callback): Promise; + checkMembership(params: Github.OrgsCheckMembershipParams, callback?: Github.Callback): Promise; + removeMember(params: Github.OrgsRemoveMemberParams, callback?: Github.Callback): Promise; + getPublicMembers(params: Github.OrgsGetPublicMembersParams, callback?: Github.Callback): Promise; + checkPublicMembership(params: Github.OrgsCheckPublicMembershipParams, callback?: Github.Callback): Promise; + publicizeMembership(params: Github.OrgsPublicizeMembershipParams, callback?: Github.Callback): Promise; + concealMembership(params: Github.OrgsConcealMembershipParams, callback?: Github.Callback): Promise; + getOrgMembership(params: Github.OrgsGetOrgMembershipParams, callback?: Github.Callback): Promise; + addOrgMembership(params: Github.OrgsAddOrgMembershipParams, callback?: Github.Callback): Promise; + removeOrgMembership(params: Github.OrgsRemoveOrgMembershipParams, callback?: Github.Callback): Promise; + getPendingOrgInvites(params: Github.OrgsGetPendingOrgInvitesParams, callback?: Github.Callback): Promise; + getOutsideCollaborators(params: Github.OrgsGetOutsideCollaboratorsParams, callback?: Github.Callback): Promise; + removeOutsideCollaborator(params: Github.OrgsRemoveOutsideCollaboratorParams, callback?: Github.Callback): Promise; + convertMemberToOutsideCollaborator(params: Github.OrgsConvertMemberToOutsideCollaboratorParams, callback?: Github.Callback): Promise; + getTeams(params: Github.OrgsGetTeamsParams, callback?: Github.Callback): Promise; + getTeam(params: Github.OrgsGetTeamParams, callback?: Github.Callback): Promise; + createTeam(params: Github.OrgsCreateTeamParams, callback?: Github.Callback): Promise; + editTeam(params: Github.OrgsEditTeamParams, callback?: Github.Callback): Promise; + deleteTeam(params: Github.OrgsDeleteTeamParams, callback?: Github.Callback): Promise; + getTeamMembers(params: Github.OrgsGetTeamMembersParams, callback?: Github.Callback): Promise; + getChildTeams(params: Github.OrgsGetChildTeamsParams, callback?: Github.Callback): Promise; + getTeamMembership(params: Github.OrgsGetTeamMembershipParams, callback?: Github.Callback): Promise; + addTeamMembership(params: Github.OrgsAddTeamMembershipParams, callback?: Github.Callback): Promise; + removeTeamMembership(params: Github.OrgsRemoveTeamMembershipParams, callback?: Github.Callback): Promise; + getTeamRepos(params: Github.OrgsGetTeamReposParams, callback?: Github.Callback): Promise; + getPendingTeamInvites(params: Github.OrgsGetPendingTeamInvitesParams, callback?: Github.Callback): Promise; + checkTeamRepo(params: Github.OrgsCheckTeamRepoParams, callback?: Github.Callback): Promise; + addTeamRepo(params: Github.OrgsAddTeamRepoParams, callback?: Github.Callback): Promise; + deleteTeamRepo(params: Github.OrgsDeleteTeamRepoParams, callback?: Github.Callback): Promise; + getHooks(params: Github.OrgsGetHooksParams, callback?: Github.Callback): Promise; + getHook(params: Github.OrgsGetHookParams, callback?: Github.Callback): Promise; + createHook(params: Github.OrgsCreateHookParams, callback?: Github.Callback): Promise; + editHook(params: Github.OrgsEditHookParams, callback?: Github.Callback): Promise; + pingHook(params: Github.OrgsPingHookParams, callback?: Github.Callback): Promise; + deleteHook(params: Github.OrgsDeleteHookParams, callback?: Github.Callback): Promise; + getBlockedUsers(params: Github.OrgsGetBlockedUsersParams, callback?: Github.Callback): Promise; + checkBlockedUser(params: Github.OrgsCheckBlockedUserParams, callback?: Github.Callback): Promise; + blockUser(params: Github.OrgsBlockUserParams, callback?: Github.Callback): Promise; + unblockUser(params: Github.OrgsUnblockUserParams, callback?: Github.Callback): Promise; + }; + projects: { + getRepoProjects(params: Github.ProjectsGetRepoProjectsParams, callback?: Github.Callback): Promise; + getOrgProjects(params: Github.ProjectsGetOrgProjectsParams, callback?: Github.Callback): Promise; + getProject(params: Github.ProjectsGetProjectParams, callback?: Github.Callback): Promise; + createRepoProject(params: Github.ProjectsCreateRepoProjectParams, callback?: Github.Callback): Promise; + createOrgProject(params: Github.ProjectsCreateOrgProjectParams, callback?: Github.Callback): Promise; + updateProject(params: Github.ProjectsUpdateProjectParams, callback?: Github.Callback): Promise; + deleteProject(params: Github.ProjectsDeleteProjectParams, callback?: Github.Callback): Promise; + getProjectCards(params: Github.ProjectsGetProjectCardsParams, callback?: Github.Callback): Promise; + getProjectCard(params: Github.ProjectsGetProjectCardParams, callback?: Github.Callback): Promise; + createProjectCard(params: Github.ProjectsCreateProjectCardParams, callback?: Github.Callback): Promise; + updateProjectCard(params: Github.ProjectsUpdateProjectCardParams, callback?: Github.Callback): Promise; + deleteProjectCard(params: Github.ProjectsDeleteProjectCardParams, callback?: Github.Callback): Promise; + moveProjectCard(params: Github.ProjectsMoveProjectCardParams, callback?: Github.Callback): Promise; + getProjectColumns(params: Github.ProjectsGetProjectColumnsParams, callback?: Github.Callback): Promise; + getProjectColumn(params: Github.ProjectsGetProjectColumnParams, callback?: Github.Callback): Promise; + createProjectColumn(params: Github.ProjectsCreateProjectColumnParams, callback?: Github.Callback): Promise; + updateProjectColumn(params: Github.ProjectsUpdateProjectColumnParams, callback?: Github.Callback): Promise; + deleteProjectColumn(params: Github.ProjectsDeleteProjectColumnParams, callback?: Github.Callback): Promise; + moveProjectColumn(params: Github.ProjectsMoveProjectColumnParams, callback?: Github.Callback): Promise; + }; + pullRequests: { + get(params: Github.PullRequestsGetParams, callback?: Github.Callback): Promise; + create(params: Github.PullRequestsCreateParams, callback?: Github.Callback): Promise; + update(params: Github.PullRequestsUpdateParams, callback?: Github.Callback): Promise; + merge(params: Github.PullRequestsMergeParams, callback?: Github.Callback): Promise; + getAll(params: Github.PullRequestsGetAllParams, callback?: Github.Callback): Promise; + createFromIssue(params: Github.PullRequestsCreateFromIssueParams, callback?: Github.Callback): Promise; + getCommits(params: Github.PullRequestsGetCommitsParams, callback?: Github.Callback): Promise; + getFiles(params: Github.PullRequestsGetFilesParams, callback?: Github.Callback): Promise; + checkMerged(params: Github.PullRequestsCheckMergedParams, callback?: Github.Callback): Promise; + getReviews(params: Github.PullRequestsGetReviewsParams, callback?: Github.Callback): Promise; + getReview(params: Github.PullRequestsGetReviewParams, callback?: Github.Callback): Promise; + deletePendingReview(params: Github.PullRequestsDeletePendingReviewParams, callback?: Github.Callback): Promise; + getReviewComments(params: Github.PullRequestsGetReviewCommentsParams, callback?: Github.Callback): Promise; + createReview(params: Github.PullRequestsCreateReviewParams, callback?: Github.Callback): Promise; + submitReview(params: Github.PullRequestsSubmitReviewParams, callback?: Github.Callback): Promise; + dismissReview(params: Github.PullRequestsDismissReviewParams, callback?: Github.Callback): Promise; + getComments(params: Github.PullRequestsGetCommentsParams, callback?: Github.Callback): Promise; + getCommentsForRepo(params: Github.PullRequestsGetCommentsForRepoParams, callback?: Github.Callback): Promise; + getComment(params: Github.PullRequestsGetCommentParams, callback?: Github.Callback): Promise; + createComment(params: Github.PullRequestsCreateCommentParams, callback?: Github.Callback): Promise; + createCommentReply(params: Github.PullRequestsCreateCommentReplyParams, callback?: Github.Callback): Promise; + editComment(params: Github.PullRequestsEditCommentParams, callback?: Github.Callback): Promise; + deleteComment(params: Github.PullRequestsDeleteCommentParams, callback?: Github.Callback): Promise; + getReviewRequests(params: Github.PullRequestsGetReviewRequestsParams, callback?: Github.Callback): Promise; + createReviewRequest(params: Github.PullRequestsCreateReviewRequestParams, callback?: Github.Callback): Promise; + deleteReviewRequest(params: Github.PullRequestsDeleteReviewRequestParams, callback?: Github.Callback): Promise; + }; + reactions: { + delete(params: Github.ReactionsDeleteParams, callback?: Github.Callback): Promise; + getForCommitComment(params: Github.ReactionsGetForCommitCommentParams, callback?: Github.Callback): Promise; + createForCommitComment(params: Github.ReactionsCreateForCommitCommentParams, callback?: Github.Callback): Promise; + getForIssue(params: Github.ReactionsGetForIssueParams, callback?: Github.Callback): Promise; + createForIssue(params: Github.ReactionsCreateForIssueParams, callback?: Github.Callback): Promise; + getForIssueComment(params: Github.ReactionsGetForIssueCommentParams, callback?: Github.Callback): Promise; + createForIssueComment(params: Github.ReactionsCreateForIssueCommentParams, callback?: Github.Callback): Promise; + getForPullRequestReviewComment(params: Github.ReactionsGetForPullRequestReviewCommentParams, callback?: Github.Callback): Promise; + createForPullRequestReviewComment(params: Github.ReactionsCreateForPullRequestReviewCommentParams, callback?: Github.Callback): Promise; + }; + repos: { + create(params: Github.ReposCreateParams, callback?: Github.Callback): Promise; + get(params: Github.ReposGetParams, callback?: Github.Callback): Promise; + edit(params: Github.ReposEditParams, callback?: Github.Callback): Promise; + delete(params: Github.ReposDeleteParams, callback?: Github.Callback): Promise; + fork(params: Github.ReposForkParams, callback?: Github.Callback): Promise; + merge(params: Github.ReposMergeParams, callback?: Github.Callback): Promise; + getAll(params: Github.ReposGetAllParams, callback?: Github.Callback): Promise; + getForUser(params: Github.ReposGetForUserParams, callback?: Github.Callback): Promise; + getForOrg(params: Github.ReposGetForOrgParams, callback?: Github.Callback): Promise; + getPublic(params: Github.ReposGetPublicParams, callback?: Github.Callback): Promise; + createForOrg(params: Github.ReposCreateForOrgParams, callback?: Github.Callback): Promise; + getById(params: Github.ReposGetByIdParams, callback?: Github.Callback): Promise; + getTopics(params: Github.ReposGetTopicsParams, callback?: Github.Callback): Promise; + replaceTopics(params: Github.ReposReplaceTopicsParams, callback?: Github.Callback): Promise; + getContributors(params: Github.ReposGetContributorsParams, callback?: Github.Callback): Promise; + getLanguages(params: Github.ReposGetLanguagesParams, callback?: Github.Callback): Promise; + getTeams(params: Github.ReposGetTeamsParams, callback?: Github.Callback): Promise; + getTags(params: Github.ReposGetTagsParams, callback?: Github.Callback): Promise; + getBranches(params: Github.ReposGetBranchesParams, callback?: Github.Callback): Promise; + getBranch(params: Github.ReposGetBranchParams, callback?: Github.Callback): Promise; + getBranchProtection(params: Github.ReposGetBranchProtectionParams, callback?: Github.Callback): Promise; + updateBranchProtection(params: Github.ReposUpdateBranchProtectionParams, callback?: Github.Callback): Promise; + removeBranchProtection(params: Github.ReposRemoveBranchProtectionParams, callback?: Github.Callback): Promise; + getProtectedBranchRequiredStatusChecks(params: Github.ReposGetProtectedBranchRequiredStatusChecksParams, callback?: Github.Callback): Promise; + updateProtectedBranchRequiredStatusChecks(params: Github.ReposUpdateProtectedBranchRequiredStatusChecksParams, callback?: Github.Callback): Promise; + removeProtectedBranchRequiredStatusChecks(params: Github.ReposRemoveProtectedBranchRequiredStatusChecksParams, callback?: Github.Callback): Promise; + getProtectedBranchRequiredStatusChecksContexts(params: Github.ReposGetProtectedBranchRequiredStatusChecksContextsParams, callback?: Github.Callback): Promise; + replaceProtectedBranchRequiredStatusChecksContexts(params: Github.ReposReplaceProtectedBranchRequiredStatusChecksContextsParams, callback?: Github.Callback): Promise; + addProtectedBranchRequiredStatusChecksContexts(params: Github.ReposAddProtectedBranchRequiredStatusChecksContextsParams, callback?: Github.Callback): Promise; + removeProtectedBranchRequiredStatusChecksContexts(params: Github.ReposRemoveProtectedBranchRequiredStatusChecksContextsParams, callback?: Github.Callback): Promise; + getProtectedBranchPullRequestReviewEnforcement(params: Github.ReposGetProtectedBranchPullRequestReviewEnforcementParams, callback?: Github.Callback): Promise; + updateProtectedBranchPullRequestReviewEnforcement(params: Github.ReposUpdateProtectedBranchPullRequestReviewEnforcementParams, callback?: Github.Callback): Promise; + removeProtectedBranchPullRequestReviewEnforcement(params: Github.ReposRemoveProtectedBranchPullRequestReviewEnforcementParams, callback?: Github.Callback): Promise; + getProtectedBranchAdminEnforcement(params: Github.ReposGetProtectedBranchAdminEnforcementParams, callback?: Github.Callback): Promise; + addProtectedBranchAdminEnforcement(params: Github.ReposAddProtectedBranchAdminEnforcementParams, callback?: Github.Callback): Promise; + removeProtectedBranchAdminEnforcement(params: Github.ReposRemoveProtectedBranchAdminEnforcementParams, callback?: Github.Callback): Promise; + getProtectedBranchRestrictions(params: Github.ReposGetProtectedBranchRestrictionsParams, callback?: Github.Callback): Promise; + removeProtectedBranchRestrictions(params: Github.ReposRemoveProtectedBranchRestrictionsParams, callback?: Github.Callback): Promise; + getProtectedBranchTeamRestrictions(params: Github.ReposGetProtectedBranchTeamRestrictionsParams, callback?: Github.Callback): Promise; + replaceProtectedBranchTeamRestrictions(params: Github.ReposReplaceProtectedBranchTeamRestrictionsParams, callback?: Github.Callback): Promise; + addProtectedBranchTeamRestrictions(params: Github.ReposAddProtectedBranchTeamRestrictionsParams, callback?: Github.Callback): Promise; + removeProtectedBranchTeamRestrictions(params: Github.ReposRemoveProtectedBranchTeamRestrictionsParams, callback?: Github.Callback): Promise; + getProtectedBranchUserRestrictions(params: Github.ReposGetProtectedBranchUserRestrictionsParams, callback?: Github.Callback): Promise; + replaceProtectedBranchUserRestrictions(params: Github.ReposReplaceProtectedBranchUserRestrictionsParams, callback?: Github.Callback): Promise; + addProtectedBranchUserRestrictions(params: Github.ReposAddProtectedBranchUserRestrictionsParams, callback?: Github.Callback): Promise; + removeProtectedBranchUserRestrictions(params: Github.ReposRemoveProtectedBranchUserRestrictionsParams, callback?: Github.Callback): Promise; + getCollaborators(params: Github.ReposGetCollaboratorsParams, callback?: Github.Callback): Promise; + checkCollaborator(params: Github.ReposCheckCollaboratorParams, callback?: Github.Callback): Promise; + reviewUserPermissionLevel(params: Github.ReposReviewUserPermissionLevelParams, callback?: Github.Callback): Promise; + addCollaborator(params: Github.ReposAddCollaboratorParams, callback?: Github.Callback): Promise; + removeCollaborator(params: Github.ReposRemoveCollaboratorParams, callback?: Github.Callback): Promise; + getAllCommitComments(params: Github.ReposGetAllCommitCommentsParams, callback?: Github.Callback): Promise; + getCommitComments(params: Github.ReposGetCommitCommentsParams, callback?: Github.Callback): Promise; + createCommitComment(params: Github.ReposCreateCommitCommentParams, callback?: Github.Callback): Promise; + getCommitComment(params: Github.ReposGetCommitCommentParams, callback?: Github.Callback): Promise; + updateCommitComment(params: Github.ReposUpdateCommitCommentParams, callback?: Github.Callback): Promise; + deleteCommitComment(params: Github.ReposDeleteCommitCommentParams, callback?: Github.Callback): Promise; + getCommunityProfileMetrics(params: Github.ReposGetCommunityProfileMetricsParams, callback?: Github.Callback): Promise; + getCommits(params: Github.ReposGetCommitsParams, callback?: Github.Callback): Promise; + getCommit(params: Github.ReposGetCommitParams, callback?: Github.Callback): Promise; + getShaOfCommitRef(params: Github.ReposGetShaOfCommitRefParams, callback?: Github.Callback): Promise; + compareCommits(params: Github.ReposCompareCommitsParams, callback?: Github.Callback): Promise; + getReadme(params: Github.ReposGetReadmeParams, callback?: Github.Callback): Promise; + getContent(params: Github.ReposGetContentParams, callback?: Github.Callback): Promise; + createFile(params: Github.ReposCreateFileParams, callback?: Github.Callback): Promise; + updateFile(params: Github.ReposUpdateFileParams, callback?: Github.Callback): Promise; + deleteFile(params: Github.ReposDeleteFileParams, callback?: Github.Callback): Promise; + getArchiveLink(params: Github.ReposGetArchiveLinkParams, callback?: Github.Callback): Promise; + getDeployKeys(params: Github.ReposGetDeployKeysParams, callback?: Github.Callback): Promise; + getDeployKey(params: Github.ReposGetDeployKeyParams, callback?: Github.Callback): Promise; + addDeployKey(params: Github.ReposAddDeployKeyParams, callback?: Github.Callback): Promise; + deleteDeployKey(params: Github.ReposDeleteDeployKeyParams, callback?: Github.Callback): Promise; + getDeployments(params: Github.ReposGetDeploymentsParams, callback?: Github.Callback): Promise; + getDeployment(params: Github.ReposGetDeploymentParams, callback?: Github.Callback): Promise; + createDeployment(params: Github.ReposCreateDeploymentParams, callback?: Github.Callback): Promise; + getDeploymentStatuses(params: Github.ReposGetDeploymentStatusesParams, callback?: Github.Callback): Promise; + getDeploymentStatus(params: Github.ReposGetDeploymentStatusParams, callback?: Github.Callback): Promise; + createDeploymentStatus(params: Github.ReposCreateDeploymentStatusParams, callback?: Github.Callback): Promise; + getDownloads(params: Github.ReposGetDownloadsParams, callback?: Github.Callback): Promise; + getDownload(params: Github.ReposGetDownloadParams, callback?: Github.Callback): Promise; + deleteDownload(params: Github.ReposDeleteDownloadParams, callback?: Github.Callback): Promise; + getForks(params: Github.ReposGetForksParams, callback?: Github.Callback): Promise; + getInvites(params: Github.ReposGetInvitesParams, callback?: Github.Callback): Promise; + deleteInvite(params: Github.ReposDeleteInviteParams, callback?: Github.Callback): Promise; + updateInvite(params: Github.ReposUpdateInviteParams, callback?: Github.Callback): Promise; + getPages(params: Github.ReposGetPagesParams, callback?: Github.Callback): Promise; + requestPageBuild(params: Github.ReposRequestPageBuildParams, callback?: Github.Callback): Promise; + getPagesBuilds(params: Github.ReposGetPagesBuildsParams, callback?: Github.Callback): Promise; + getLatestPagesBuild(params: Github.ReposGetLatestPagesBuildParams, callback?: Github.Callback): Promise; + getPagesBuild(params: Github.ReposGetPagesBuildParams, callback?: Github.Callback): Promise; + getReleases(params: Github.ReposGetReleasesParams, callback?: Github.Callback): Promise; + getRelease(params: Github.ReposGetReleaseParams, callback?: Github.Callback): Promise; + getLatestRelease(params: Github.ReposGetLatestReleaseParams, callback?: Github.Callback): Promise; + getReleaseByTag(params: Github.ReposGetReleaseByTagParams, callback?: Github.Callback): Promise; + createRelease(params: Github.ReposCreateReleaseParams, callback?: Github.Callback): Promise; + editRelease(params: Github.ReposEditReleaseParams, callback?: Github.Callback): Promise; + deleteRelease(params: Github.ReposDeleteReleaseParams, callback?: Github.Callback): Promise; + getAssets(params: Github.ReposGetAssetsParams, callback?: Github.Callback): Promise; + uploadAsset(params: Github.ReposUploadAssetParams, callback?: Github.Callback): Promise; + getAsset(params: Github.ReposGetAssetParams, callback?: Github.Callback): Promise; + editAsset(params: Github.ReposEditAssetParams, callback?: Github.Callback): Promise; + deleteAsset(params: Github.ReposDeleteAssetParams, callback?: Github.Callback): Promise; + getStatsContributors(params: Github.ReposGetStatsContributorsParams, callback?: Github.Callback): Promise; + getStatsCommitActivity(params: Github.ReposGetStatsCommitActivityParams, callback?: Github.Callback): Promise; + getStatsCodeFrequency(params: Github.ReposGetStatsCodeFrequencyParams, callback?: Github.Callback): Promise; + getStatsParticipation(params: Github.ReposGetStatsParticipationParams, callback?: Github.Callback): Promise; + getStatsPunchCard(params: Github.ReposGetStatsPunchCardParams, callback?: Github.Callback): Promise; + createStatus(params: Github.ReposCreateStatusParams, callback?: Github.Callback): Promise; + getStatuses(params: Github.ReposGetStatusesParams, callback?: Github.Callback): Promise; + getCombinedStatusForRef(params: Github.ReposGetCombinedStatusForRefParams, callback?: Github.Callback): Promise; + getReferrers(params: Github.ReposGetReferrersParams, callback?: Github.Callback): Promise; + getPaths(params: Github.ReposGetPathsParams, callback?: Github.Callback): Promise; + getViews(params: Github.ReposGetViewsParams, callback?: Github.Callback): Promise; + getClones(params: Github.ReposGetClonesParams, callback?: Github.Callback): Promise; + getHooks(params: Github.ReposGetHooksParams, callback?: Github.Callback): Promise; + getHook(params: Github.ReposGetHookParams, callback?: Github.Callback): Promise; + createHook(params: Github.ReposCreateHookParams, callback?: Github.Callback): Promise; + editHook(params: Github.ReposEditHookParams, callback?: Github.Callback): Promise; + testHook(params: Github.ReposTestHookParams, callback?: Github.Callback): Promise; + pingHook(params: Github.ReposPingHookParams, callback?: Github.Callback): Promise; + deleteHook(params: Github.ReposDeleteHookParams, callback?: Github.Callback): Promise; + }; + search: { + repos(params: Github.SearchReposParams, callback?: Github.Callback): Promise; + code(params: Github.SearchCodeParams, callback?: Github.Callback): Promise; + commits(params: Github.SearchCommitsParams, callback?: Github.Callback): Promise; + issues(params: Github.SearchIssuesParams, callback?: Github.Callback): Promise; + users(params: Github.SearchUsersParams, callback?: Github.Callback): Promise; + email(params: Github.SearchEmailParams, callback?: Github.Callback): Promise; + }; + users: { + get(params: Github.EmptyParams, callback?: Github.Callback): Promise; + update(params: Github.UsersUpdateParams, callback?: Github.Callback): Promise; + promote(params: Github.UsersPromoteParams, callback?: Github.Callback): Promise; + demote(params: Github.UsersDemoteParams, callback?: Github.Callback): Promise; + suspend(params: Github.UsersSuspendParams, callback?: Github.Callback): Promise; + unsuspend(params: Github.UsersUnsuspendParams, callback?: Github.Callback): Promise; + getForUser(params: Github.UsersGetForUserParams, callback?: Github.Callback): Promise; + getById(params: Github.UsersGetByIdParams, callback?: Github.Callback): Promise; + getAll(params: Github.UsersGetAllParams, callback?: Github.Callback): Promise; + getOrgs(params: Github.UsersGetOrgsParams, callback?: Github.Callback): Promise; + getOrgMemberships(params: Github.UsersGetOrgMembershipsParams, callback?: Github.Callback): Promise; + getOrgMembership(params: Github.UsersGetOrgMembershipParams, callback?: Github.Callback): Promise; + editOrgMembership(params: Github.UsersEditOrgMembershipParams, callback?: Github.Callback): Promise; + getTeams(params: Github.UsersGetTeamsParams, callback?: Github.Callback): Promise; + getEmails(params: Github.UsersGetEmailsParams, callback?: Github.Callback): Promise; + getPublicEmails(params: Github.UsersGetPublicEmailsParams, callback?: Github.Callback): Promise; + addEmails(params: Github.UsersAddEmailsParams, callback?: Github.Callback): Promise; + deleteEmails(params: Github.UsersDeleteEmailsParams, callback?: Github.Callback): Promise; + togglePrimaryEmailVisibility(params: Github.EmptyParams, callback?: Github.Callback): Promise; + getFollowersForUser(params: Github.UsersGetFollowersForUserParams, callback?: Github.Callback): Promise; + getFollowers(params: Github.UsersGetFollowersParams, callback?: Github.Callback): Promise; + getFollowingForUser(params: Github.UsersGetFollowingForUserParams, callback?: Github.Callback): Promise; + getFollowing(params: Github.UsersGetFollowingParams, callback?: Github.Callback): Promise; + checkFollowing(params: Github.UsersCheckFollowingParams, callback?: Github.Callback): Promise; + checkIfOneFollowersOther(params: Github.UsersCheckIfOneFollowersOtherParams, callback?: Github.Callback): Promise; + followUser(params: Github.UsersFollowUserParams, callback?: Github.Callback): Promise; + unfollowUser(params: Github.UsersUnfollowUserParams, callback?: Github.Callback): Promise; + getKeysForUser(params: Github.UsersGetKeysForUserParams, callback?: Github.Callback): Promise; + getKeys(params: Github.UsersGetKeysParams, callback?: Github.Callback): Promise; + getKey(params: Github.UsersGetKeyParams, callback?: Github.Callback): Promise; + createKey(params: Github.UsersCreateKeyParams, callback?: Github.Callback): Promise; + deleteKey(params: Github.UsersDeleteKeyParams, callback?: Github.Callback): Promise; + getGpgKeysForUser(params: Github.UsersGetGpgKeysForUserParams, callback?: Github.Callback): Promise; + getGpgKeys(params: Github.UsersGetGpgKeysParams, callback?: Github.Callback): Promise; + getGpgKey(params: Github.UsersGetGpgKeyParams, callback?: Github.Callback): Promise; + createGpgKey(params: Github.UsersCreateGpgKeyParams, callback?: Github.Callback): Promise; + deleteGpgKey(params: Github.UsersDeleteGpgKeyParams, callback?: Github.Callback): Promise; + getBlockedUsers(params: Github.EmptyParams, callback?: Github.Callback): Promise; + checkBlockedUser(params: Github.UsersCheckBlockedUserParams, callback?: Github.Callback): Promise; + blockUser(params: Github.UsersBlockUserParams, callback?: Github.Callback): Promise; + unblockUser(params: Github.UsersUnblockUserParams, callback?: Github.Callback): Promise; + getRepoInvites(params: Github.EmptyParams, callback?: Github.Callback): Promise; + acceptRepoInvite(params: Github.UsersAcceptRepoInviteParams, callback?: Github.Callback): Promise; + declineRepoInvite(params: Github.UsersDeclineRepoInviteParams, callback?: Github.Callback): Promise; + getInstallations(params: Github.UsersGetInstallationsParams, callback?: Github.Callback): Promise; + getInstallationRepos(params: Github.UsersGetInstallationReposParams, callback?: Github.Callback): Promise; + addRepoToInstallation(params: Github.UsersAddRepoToInstallationParams, callback?: Github.Callback): Promise; + removeRepoFromInstallation(params: Github.UsersRemoveRepoFromInstallationParams, callback?: Github.Callback): Promise; + getMarketplacePurchases(params: Github.UsersGetMarketplacePurchasesParams, callback?: Github.Callback): Promise; + getMarketplaceStubbedPurchases(params: Github.UsersGetMarketplaceStubbedPurchasesParams, callback?: Github.Callback): Promise; + }; + enterprise: { + stats(params: Github.EnterpriseStatsParams, callback?: Github.Callback): Promise; + updateLdapForUser(params: Github.EnterpriseUpdateLdapForUserParams, callback?: Github.Callback): Promise; + syncLdapForUser(params: Github.EnterpriseSyncLdapForUserParams, callback?: Github.Callback): Promise; + updateLdapForTeam(params: Github.EnterpriseUpdateLdapForTeamParams, callback?: Github.Callback): Promise; + syncLdapForTeam(params: Github.EnterpriseSyncLdapForTeamParams, callback?: Github.Callback): Promise; + getLicense(params: Github.EmptyParams, callback?: Github.Callback): Promise; + getPreReceiveEnvironment(params: Github.EnterpriseGetPreReceiveEnvironmentParams, callback?: Github.Callback): Promise; + getPreReceiveEnvironments(params: Github.EmptyParams, callback?: Github.Callback): Promise; + createPreReceiveEnvironment(params: Github.EnterpriseCreatePreReceiveEnvironmentParams, callback?: Github.Callback): Promise; + editPreReceiveEnvironment(params: Github.EnterpriseEditPreReceiveEnvironmentParams, callback?: Github.Callback): Promise; + deletePreReceiveEnvironment(params: Github.EnterpriseDeletePreReceiveEnvironmentParams, callback?: Github.Callback): Promise; + getPreReceiveEnvironmentDownloadStatus(params: Github.EnterpriseGetPreReceiveEnvironmentDownloadStatusParams, callback?: Github.Callback): Promise; + triggerPreReceiveEnvironmentDownload(params: Github.EnterpriseTriggerPreReceiveEnvironmentDownloadParams, callback?: Github.Callback): Promise; + getPreReceiveHook(params: Github.EnterpriseGetPreReceiveHookParams, callback?: Github.Callback): Promise; + getPreReceiveHooks(params: Github.EmptyParams, callback?: Github.Callback): Promise; + createPreReceiveHook(params: Github.EnterpriseCreatePreReceiveHookParams, callback?: Github.Callback): Promise; + editPreReceiveHook(params: Github.EnterpriseEditPreReceiveHookParams, callback?: Github.Callback): Promise; + deletePreReceiveHook(params: Github.EnterpriseDeletePreReceiveHookParams, callback?: Github.Callback): Promise; + queueIndexingJob(params: Github.EnterpriseQueueIndexingJobParams, callback?: Github.Callback): Promise; + createOrg(params: Github.EnterpriseCreateOrgParams, callback?: Github.Callback): Promise; + }; +} + +declare module "octokit-rest-es3" { + export = Github; +} \ No newline at end of file From 29cb502be5d0795ee82756510323a0a8e9a9287f Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Thu, 1 Mar 2018 12:43:20 +0000 Subject: [PATCH 0194/1008] Make it so we don't run tasks inside tasks, and instead just run one chain (so it can fail and we can catch it) --- src/GitHub.Api/Installer/GitInstaller.cs | 56 +++++++++++++----------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 8fb339f56..165e3e0af 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -111,45 +111,51 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) return; } - new ActionTask(cancellationToken, () => { - if (IsGitExtracted()) + var task = new FuncTask(cancellationToken, () => + { + if (!IsGitExtracted()) { Logger.Trace("SetupGitIfNeeded: Skipped"); - onSuccess.PreviousResult = installDetails.GitExecutablePath; - onSuccess.Start(); - } - else - { - ExtractPortableGit(onSuccess, onFailure); + throw new Exception(); } - }).Start(); + return installDetails.GitExecutablePath; + }); + var extractTask = ExtractPortableGit(); + extractTask.Then(onSuccess, TaskRunOptions.OnSuccess, taskIsTopOfChain: true); + extractTask.Then(onFailure, TaskRunOptions.OnFailure, taskIsTopOfChain: true); + + task.Then(onSuccess, TaskRunOptions.OnSuccess, taskIsTopOfChain: true); + task.Then(extractTask, TaskRunOptions.OnFailure, taskIsTopOfChain: true); + task.Start(); } - private void ExtractPortableGit(ActionTask onSuccess, ITask onFailure) + private FuncTask ExtractPortableGit() { - ITask downloadFilesTask = null; - if ((gitArchiveFilePath == null) || (gitLfsArchivePath == null)) - { - downloadFilesTask = CreateDownloadTask(); - } - var tempZipExtractPath = NPath.CreateTempDirectory("git_zip_extract_zip_paths"); var gitExtractPath = tempZipExtractPath.Combine("git").CreateDirectory(); var gitLfsExtractPath = tempZipExtractPath.Combine("git-lfs").CreateDirectory(); - var resultTask = new UnzipTask(cancellationToken, gitArchiveFilePath, gitExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitExtractedMD5) - .Then(new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails .GitLfsExtractedMD5)) - .Then(s => MoveGitAndLfs(gitExtractPath, gitLfsExtractPath, tempZipExtractPath)); - - resultTask.Then(onFailure, TaskRunOptions.OnFailure); - resultTask.Then(onSuccess, TaskRunOptions.OnSuccess); + var unzipTasks = CreateUnzipTasks(gitExtractPath, gitLfsExtractPath, tempZipExtractPath); - if (downloadFilesTask != null) + if (gitArchiveFilePath == null || gitLfsArchivePath == null) { - resultTask = downloadFilesTask.Then(resultTask); + var downloadFilesTask = CreateDownloadTask(); + unzipTasks = downloadFilesTask.Then(unzipTasks); } - resultTask.Start(); + return unzipTasks; + } + + private FuncTask CreateUnzipTasks(NPath gitExtractPath, NPath gitLfsExtractPath, NPath tempZipExtractPath) + { + var unzipGitTask = new UnzipTask(cancellationToken, gitArchiveFilePath, gitExtractPath, sharpZipLibHelper, + environment.FileSystem, GitInstallDetails.GitExtractedMD5); + var unzipGitLfsTask = new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper, + environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5); + var moveGitTask = new FuncTask(cancellationToken, () => MoveGitAndLfs(gitExtractPath, gitLfsExtractPath, tempZipExtractPath)); + return unzipGitTask + .Then(unzipGitLfsTask) + .Then(moveGitTask); } private NPath MoveGitAndLfs(NPath gitExtractPath, NPath gitLfsExtractPath, NPath tempZipExtractPath) From 0d3ca28365e3f5719004e86ad54199ad319f54e2 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Wed, 28 Feb 2018 16:13:46 -0500 Subject: [PATCH 0195/1008] Let me stop here for a moment --- octorun/LICENSE | 21 - octorun/bin/octorun | 5 - octorun/bin/octorun-login | 3 - octorun/bin/octorun-write | 3 - octorun/dist/authenticator.d.ts | 5 - octorun/dist/authenticator.js | 75 - octorun/dist/bin/app-login.d.ts | 7 - octorun/dist/bin/app-login.js | 30 - octorun/dist/bin/app-write.d.ts | 7 - octorun/dist/bin/app-write.js | 31 - octorun/dist/bin/app.d.ts | 6 - octorun/dist/bin/app.js | 20 - octorun/dist/configuration.d.ts | 5 - octorun/dist/configuration.js | 7 - octorun/dist/writer.d.ts | 3 - octorun/dist/writer.js | 12 - octorun/src/authenticator.ts | 41 - octorun/src/bin/app-login.ts | 40 - octorun/src/bin/app-write.ts | 39 - octorun/src/bin/app.ts | 26 - octorun/src/configuration.ts | 6 - octorun/src/writer.ts | 7 - octorun/test/writer-spec.ts | 34 - octorun/tsconfig.json | 22 - octorun/typings/octokit-rest-es3/index.d.ts | 3476 ------------------- 25 files changed, 3931 deletions(-) delete mode 100644 octorun/LICENSE delete mode 100644 octorun/bin/octorun delete mode 100644 octorun/bin/octorun-login delete mode 100644 octorun/bin/octorun-write delete mode 100644 octorun/dist/authenticator.d.ts delete mode 100644 octorun/dist/authenticator.js delete mode 100644 octorun/dist/bin/app-login.d.ts delete mode 100644 octorun/dist/bin/app-login.js delete mode 100644 octorun/dist/bin/app-write.d.ts delete mode 100644 octorun/dist/bin/app-write.js delete mode 100644 octorun/dist/bin/app.d.ts delete mode 100644 octorun/dist/bin/app.js delete mode 100644 octorun/dist/configuration.d.ts delete mode 100644 octorun/dist/configuration.js delete mode 100644 octorun/dist/writer.d.ts delete mode 100644 octorun/dist/writer.js delete mode 100644 octorun/src/authenticator.ts delete mode 100644 octorun/src/bin/app-login.ts delete mode 100644 octorun/src/bin/app-write.ts delete mode 100644 octorun/src/bin/app.ts delete mode 100644 octorun/src/configuration.ts delete mode 100644 octorun/src/writer.ts delete mode 100644 octorun/test/writer-spec.ts delete mode 100644 octorun/tsconfig.json delete mode 100644 octorun/typings/octokit-rest-es3/index.d.ts diff --git a/octorun/LICENSE b/octorun/LICENSE deleted file mode 100644 index 0776bd363..000000000 --- a/octorun/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/octorun/bin/octorun b/octorun/bin/octorun deleted file mode 100644 index 6c0fe6d04..000000000 --- a/octorun/bin/octorun +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env node - -console.log("NodeJs", process.argv[0]); - -require('../dist/bin/app.js'); diff --git a/octorun/bin/octorun-login b/octorun/bin/octorun-login deleted file mode 100644 index fe09da41a..000000000 --- a/octorun/bin/octorun-login +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env node - -require('../dist/bin/app-login.js'); diff --git a/octorun/bin/octorun-write b/octorun/bin/octorun-write deleted file mode 100644 index 62ead2886..000000000 --- a/octorun/bin/octorun-write +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env node - -require('../dist/bin/app-write.js'); diff --git a/octorun/dist/authenticator.d.ts b/octorun/dist/authenticator.d.ts deleted file mode 100644 index cc6697a38..000000000 --- a/octorun/dist/authenticator.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export declare class Authenticator { - private github; - constructor(); - createAndDeleteExistingApplicationAuthorization(): Promise; -} diff --git a/octorun/dist/authenticator.js b/octorun/dist/authenticator.js deleted file mode 100644 index c6698dc32..000000000 --- a/octorun/dist/authenticator.js +++ /dev/null @@ -1,75 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (_) try { - if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [0, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -exports.__esModule = true; -var GitHub = require("octokit-rest-es3"); -var configuration_1 = require("./configuration"); -var Authenticator = (function () { - function Authenticator() { - this.github = new GitHub({ - timeout: 0, - requestMedia: 'application/vnd.github.v3+json', - headers: { - 'user-agent': 'octokit/rest.js v1.2.3' - }, - host: 'api.github.com', - pathPrefix: '', - protocol: 'https', - port: 443 - }); - } - Authenticator.prototype.createAndDeleteExistingApplicationAuthorization = function () { - return __awaiter(this, void 0, void 0, function () { - var authParams; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - authParams = { - client_id: configuration_1.configuration.ClientId, - client_secret: configuration_1.configuration.ClientSecret, - scopes: ["user", "repo", "gist", "write:public_key"] - }; - return [4, this.github.authorization.getOrCreateAuthorizationForApp(authParams)]; - case 1: - _a.sent(); - return [2]; - } - }); - }); - }; - return Authenticator; -}()); -exports.Authenticator = Authenticator; diff --git a/octorun/dist/bin/app-login.d.ts b/octorun/dist/bin/app-login.d.ts deleted file mode 100644 index 1a4eeeebc..000000000 --- a/octorun/dist/bin/app-login.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -export declare class Write { - private program; - private package; - private authenticator; - constructor(); - initialize(): void; -} diff --git a/octorun/dist/bin/app-login.js b/octorun/dist/bin/app-login.js deleted file mode 100644 index 4bfbefe90..000000000 --- a/octorun/dist/bin/app-login.js +++ /dev/null @@ -1,30 +0,0 @@ -"use strict"; -exports.__esModule = true; -var commander = require("commander"); -var authenticator_1 = require("../authenticator"); -var Write = (function () { - function Write() { - this.program = commander; - this.package = require('../../package.json'); - this.authenticator = new authenticator_1.Authenticator(); - } - Write.prototype.initialize = function () { - this.program - .version(this.package.version) - .option('-l, --login') - .option('-t, --twoFactor') - .parse(process.argv); - if (this.program.login) { - this.authenticator.createAndDeleteExistingApplicationAuthorization(); - process.exit(); - } - else if (this.program.twoFactor) { - process.exit(); - } - this.program.help(); - }; - return Write; -}()); -exports.Write = Write; -var app = new Write(); -app.initialize(); diff --git a/octorun/dist/bin/app-write.d.ts b/octorun/dist/bin/app-write.d.ts deleted file mode 100644 index b6e272292..000000000 --- a/octorun/dist/bin/app-write.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -export declare class Write { - private program; - private package; - private writer; - constructor(); - initialize(): void; -} diff --git a/octorun/dist/bin/app-write.js b/octorun/dist/bin/app-write.js deleted file mode 100644 index fd02ec270..000000000 --- a/octorun/dist/bin/app-write.js +++ /dev/null @@ -1,31 +0,0 @@ -"use strict"; -exports.__esModule = true; -var commander = require("commander"); -var writer_1 = require("../writer"); -var Write = (function () { - function Write() { - this.program = commander; - this.package = require('../../package.json'); - this.writer = new writer_1.Writer(); - } - Write.prototype.initialize = function () { - this.program - .version(this.package.version) - .option('-m, --message [value]', 'Say hello!') - .parse(process.argv); - if (this.program.message != null) { - if (typeof this.program.message !== 'string') { - this.writer.write(); - } - else { - this.writer.write(this.program.message); - } - process.exit(); - } - this.program.help(); - }; - return Write; -}()); -exports.Write = Write; -var app = new Write(); -app.initialize(); diff --git a/octorun/dist/bin/app.d.ts b/octorun/dist/bin/app.d.ts deleted file mode 100644 index 65223902d..000000000 --- a/octorun/dist/bin/app.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -export declare class App { - private program; - private package; - constructor(); - initialize(): void; -} diff --git a/octorun/dist/bin/app.js b/octorun/dist/bin/app.js deleted file mode 100644 index 10a9c9caf..000000000 --- a/octorun/dist/bin/app.js +++ /dev/null @@ -1,20 +0,0 @@ -"use strict"; -exports.__esModule = true; -var commander = require("commander"); -var App = (function () { - function App() { - this.program = commander; - this.package = require('../../package.json'); - } - App.prototype.initialize = function () { - this.program - .version(this.package.version) - .command('login [-h|-2fa]', 'Authenticate') - .command('write [message]', 'say hello!') - .parse(process.argv); - }; - return App; -}()); -exports.App = App; -var app = new App(); -app.initialize(); diff --git a/octorun/dist/configuration.d.ts b/octorun/dist/configuration.d.ts deleted file mode 100644 index 93e15f619..000000000 --- a/octorun/dist/configuration.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare const configuration: { - ClientId: any; - ClientSecret: any; -}; -export { configuration }; diff --git a/octorun/dist/configuration.js b/octorun/dist/configuration.js deleted file mode 100644 index 1a3d3ed1c..000000000 --- a/octorun/dist/configuration.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict"; -exports.__esModule = true; -var configuration = { - ClientId: process.env.OCTOKIT_CLIENT_ID, - ClientSecret: process.env.OCTOKIT_CLIENT_SECRET -}; -exports.configuration = configuration; diff --git a/octorun/dist/writer.d.ts b/octorun/dist/writer.d.ts deleted file mode 100644 index 8373b156f..000000000 --- a/octorun/dist/writer.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export declare class Writer { - write(message?: String): void; -} diff --git a/octorun/dist/writer.js b/octorun/dist/writer.js deleted file mode 100644 index e5d55d015..000000000 --- a/octorun/dist/writer.js +++ /dev/null @@ -1,12 +0,0 @@ -"use strict"; -exports.__esModule = true; -var Writer = (function () { - function Writer() { - } - Writer.prototype.write = function (message) { - if (message === void 0) { message = "Hello World!"; } - console.log(message); - }; - return Writer; -}()); -exports.Writer = Writer; diff --git a/octorun/src/authenticator.ts b/octorun/src/authenticator.ts deleted file mode 100644 index 2e47f5109..000000000 --- a/octorun/src/authenticator.ts +++ /dev/null @@ -1,41 +0,0 @@ -/// - -import * as GitHub from 'octokit-rest-es3'; -import { configuration } from './configuration'; - -export class Authenticator { - - private github: GitHub; - - constructor() { - - //Listed defaults from https://github.com/octokit/rest.js#options - - this.github = new GitHub({ - timeout: 0, // 0 means no request timeout - requestMedia: 'application/vnd.github.v3+json', - headers: { - 'user-agent': 'octokit/rest.js v1.2.3' // v1.2.3 will be current version - }, - - // change for custom GitHub Enterprise URL - host: 'api.github.com', - pathPrefix: '', - protocol: 'https', - port: 443, - - // Node only: advanced request options can be passed as http(s) agent - //agent: undefined - }) - } - - public async createAndDeleteExistingApplicationAuthorization() { - const authParams: GitHub.AuthorizationGetOrCreateAuthorizationForAppParams = { - client_id: configuration.ClientId, - client_secret: configuration.ClientSecret, - scopes: ["user", "repo", "gist", "write:public_key"] - }; - - await this.github.authorization.getOrCreateAuthorizationForApp(authParams); - } -} diff --git a/octorun/src/bin/app-login.ts b/octorun/src/bin/app-login.ts deleted file mode 100644 index d216709fd..000000000 --- a/octorun/src/bin/app-login.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as commander from 'commander'; -import { Authenticator } from '../authenticator'; - -export class Write { - - private program: commander.CommanderStatic; - private package: any; - private authenticator: Authenticator; - - constructor() { - this.program = commander; - this.package = require('../../package.json'); - this.authenticator = new Authenticator(); - } - - public initialize() { - this.program - .version(this.package.version) - .option('-l, --login') - .option('-t, --twoFactor') - .parse(process.argv); - - if (this.program.login) { - - this.authenticator.createAndDeleteExistingApplicationAuthorization() - - process.exit(); - } - else if (this.program.twoFactor) { - - process.exit(); - } - - this.program.help(); - } - -} - -let app = new Write(); -app.initialize(); diff --git a/octorun/src/bin/app-write.ts b/octorun/src/bin/app-write.ts deleted file mode 100644 index 743f97f54..000000000 --- a/octorun/src/bin/app-write.ts +++ /dev/null @@ -1,39 +0,0 @@ -import * as commander from 'commander'; -import { Writer } from '../writer'; - -export class Write { - - private program: commander.CommanderStatic; - private package: any; - private writer: Writer; - - constructor() { - this.program = commander; - this.package = require('../../package.json'); - this.writer = new Writer(); - } - - public initialize() { - this.program - .version(this.package.version) - .option('-m, --message [value]', 'Say hello!') - .parse(process.argv); - - if (this.program.message != null) { - - if (typeof this.program.message !== 'string') { - this.writer.write(); - } else { - this.writer.write(this.program.message); - } - - process.exit(); - } - - this.program.help(); - } - -} - -let app = new Write(); -app.initialize(); diff --git a/octorun/src/bin/app.ts b/octorun/src/bin/app.ts deleted file mode 100644 index 5bc468e57..000000000 --- a/octorun/src/bin/app.ts +++ /dev/null @@ -1,26 +0,0 @@ -//require('dotenv').config(); - -import * as commander from 'commander'; - -export class App { - - private program: commander.CommanderStatic; - private package: any; - - constructor() { - this.program = commander; - this.package = require('../../package.json'); - } - - public initialize() { - this.program - .version(this.package.version) - .command('login [-h|-2fa]', 'Authenticate') - .command('write [message]', 'say hello!') - .parse(process.argv); - } - -} - -let app = new App(); -app.initialize(); diff --git a/octorun/src/configuration.ts b/octorun/src/configuration.ts deleted file mode 100644 index b72e19aed..000000000 --- a/octorun/src/configuration.ts +++ /dev/null @@ -1,6 +0,0 @@ -const configuration = { - ClientId: process.env.OCTOKIT_CLIENT_ID, - ClientSecret: process.env.OCTOKIT_CLIENT_SECRET, -}; - -export { configuration }; \ No newline at end of file diff --git a/octorun/src/writer.ts b/octorun/src/writer.ts deleted file mode 100644 index 2a15fdff9..000000000 --- a/octorun/src/writer.ts +++ /dev/null @@ -1,7 +0,0 @@ -export class Writer { - - public write(message: String = "Hello World!") { - console.log(message); - } - -} diff --git a/octorun/test/writer-spec.ts b/octorun/test/writer-spec.ts deleted file mode 100644 index b85289ec6..000000000 --- a/octorun/test/writer-spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Writer } from '../src/writer'; -import * as chai from 'chai'; -import * as sinon from 'sinon'; - -const assert = chai.assert; - -describe('Writer', () => { - describe('#write()', () => { - it('should write a message', () => { - - let spy = sinon.spy(console, 'log'); - - var writer = new Writer(); - writer.write('I am being tested!'); - - assert(spy.calledWith('I am being tested!')); - - spy.restore(); - - }); - it('should write a default message', () => { - - let spy = sinon.spy(console, 'log'); - - var writer = new Writer(); - writer.write(); - - assert(spy.calledWith('Hello World!')); - - spy.restore(); - - }); - }); -}); diff --git a/octorun/tsconfig.json b/octorun/tsconfig.json deleted file mode 100644 index 021d9fb8a..000000000 --- a/octorun/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compileOnSave": false, - "compilerOptions": { - "target": "es3", - "declaration": true, - "module": "commonjs", - "moduleResolution": "node", - "noImplicitAny": true, - "outDir": "./dist", - "preserveConstEnums": true, - "removeComments": true, - "lib":["es2015"] - }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules", - "!node_modules/@types", - "test/**/*-spec.ts" - ] -} diff --git a/octorun/typings/octokit-rest-es3/index.d.ts b/octorun/typings/octokit-rest-es3/index.d.ts deleted file mode 100644 index 693473ddb..000000000 --- a/octorun/typings/octokit-rest-es3/index.d.ts +++ /dev/null @@ -1,3476 +0,0 @@ -/** - * This declaration file requires TypeScript 2.1 or above. - */ -declare namespace Github { - type json = any - type date = string - - export interface AnyResponse { - /** This is the data you would see in https://developer.github.com/v3/ */ - data: any - - /** Request metadata */ - meta:{ - 'x-ratelimit-limit': string, - 'x-ratelimit-remaining': string, - 'x-ratelimit-reset': string, - 'x-github-request-id': string, - 'x-github-media-type': string, - link: string, - 'last-modified': string, - etag: string, - status: string - } - - [Symbol.iterator](): Iterator - } - - export interface EmptyParams { - } - - export interface Options { - timeout?: number; - host?: string; - pathPrefix?: string; - protocol?: string; - port?: number; - proxy?: string; - ca?: string; - headers?: {[header: string]: any}; - requestMedia?: string; - rejectUnauthorized?: boolean; - family?: number; - } - - export interface AuthBasic { - type: "basic"; - username: string; - password: string; - } - - export interface AuthOAuthToken { - type: "oauth"; - token: string; - } - - export interface AuthOAuthSecret { - type: "oauth"; - key: string; - secret: string; - } - - export interface AuthUserToken { - type: "token"; - token: string; - } - - export interface AuthJWT { - type: "integration"; - token: string; - } - - export type Auth = - | AuthBasic - | AuthOAuthToken - | AuthOAuthSecret - | AuthUserToken - | AuthJWT; - - export type Link = - | { link: string; } - | { meta: { link: string; }; } - | string; - - export interface Callback { - (error: Error | null, result: any): any; - } - - - export type AuthorizationGetParams = - & { - id: string; - }; - export type AuthorizationCreateParams = - & { - scopes?: string[]; - note?: string; - note_url?: string; - client_id?: string; - client_secret?: string; - fingerprint?: string; - }; - export type AuthorizationUpdateParams = - & { - id: string; - scopes?: string[]; - add_scopes?: string[]; - remove_scopes?: string[]; - note?: string; - note_url?: string; - fingerprint?: string; - }; - export type AuthorizationDeleteParams = - & { - id: string; - }; - export type AuthorizationCheckParams = - & { - client_id?: string; - access_token: string; - }; - export type AuthorizationResetParams = - & { - client_id?: string; - access_token: string; - }; - export type AuthorizationRevokeParams = - & { - client_id?: string; - access_token: string; - }; - export type AuthorizationGetGrantsParams = - & { - page?: number; - per_page?: number; - }; - export type AuthorizationGetGrantParams = - & { - id: string; - page?: number; - per_page?: number; - }; - export type AuthorizationDeleteGrantParams = - & { - id: string; - }; - export type AuthorizationGetAllParams = - & { - page?: number; - per_page?: number; - }; - export type AuthorizationGetOrCreateAuthorizationForAppParams = - & { - client_id?: string; - client_secret: string; - scopes?: string[]; - note?: string; - note_url?: string; - fingerprint?: string; - }; - export type AuthorizationGetOrCreateAuthorizationForAppAndFingerprintParams = - & { - client_id?: string; - fingerprint?: string; - client_secret: string; - scopes?: string[]; - note?: string; - note_url?: string; - }; - export type AuthorizationRevokeGrantParams = - & { - client_id?: string; - access_token: string; - }; - export type ActivityGetEventsParams = - & { - page?: number; - per_page?: number; - }; - export type ActivityGetEventsForRepoParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ActivityGetEventsForRepoIssuesParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ActivityGetEventsForRepoNetworkParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ActivityGetEventsForOrgParams = - & { - org: string; - page?: number; - per_page?: number; - }; - export type ActivityGetEventsReceivedParams = - & { - username: string; - page?: number; - per_page?: number; - }; - export type ActivityGetEventsReceivedPublicParams = - & { - username: string; - page?: number; - per_page?: number; - }; - export type ActivityGetEventsForUserParams = - & { - username: string; - page?: number; - per_page?: number; - }; - export type ActivityGetEventsForUserPublicParams = - & { - username: string; - page?: number; - per_page?: number; - }; - export type ActivityGetEventsForUserOrgParams = - & { - username: string; - org: string; - page?: number; - per_page?: number; - }; - export type ActivityGetNotificationsParams = - & { - all?: boolean; - participating?: boolean; - since?: date; - before?: string; - }; - export type ActivityGetNotificationsForUserParams = - & { - owner: string; - repo: string; - all?: boolean; - participating?: boolean; - since?: date; - before?: string; - }; - export type ActivityMarkNotificationsAsReadParams = - & { - last_read_at?: string; - }; - export type ActivityMarkNotificationsAsReadForRepoParams = - & { - owner: string; - repo: string; - last_read_at?: string; - }; - export type ActivityGetNotificationThreadParams = - & { - id: string; - }; - export type ActivityMarkNotificationThreadAsReadParams = - & { - id: string; - }; - export type ActivityCheckNotificationThreadSubscriptionParams = - & { - id: string; - }; - export type ActivitySetNotificationThreadSubscriptionParams = - & { - id: string; - subscribed?: boolean; - ignored?: boolean; - }; - export type ActivityDeleteNotificationThreadSubscriptionParams = - & { - id: string; - }; - export type ActivityGetStargazersForRepoParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ActivityGetStarredReposForUserParams = - & { - username: string; - sort?: "created"|"updated"; - direction?: "asc"|"desc"; - page?: number; - per_page?: number; - }; - export type ActivityGetStarredReposParams = - & { - sort?: "created"|"updated"; - direction?: "asc"|"desc"; - page?: number; - per_page?: number; - }; - export type ActivityCheckStarringRepoParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ActivityStarRepoParams = - & { - owner: string; - repo: string; - }; - export type ActivityUnstarRepoParams = - & { - owner: string; - repo: string; - }; - export type ActivityGetWatchersForRepoParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ActivityGetWatchedReposForUserParams = - & { - username: string; - page?: number; - per_page?: number; - }; - export type ActivityGetWatchedReposParams = - & { - page?: number; - per_page?: number; - }; - export type ActivityGetRepoSubscriptionParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ActivitySetRepoSubscriptionParams = - & { - owner: string; - repo: string; - subscribed?: boolean; - ignored?: boolean; - }; - export type ActivityUnwatchRepoParams = - & { - owner: string; - repo: string; - }; - export type GistsGetParams = - & { - id: string; - }; - export type GistsCreateParams = - & { - files: json; - description?: string; - public: boolean; - }; - export type GistsEditParams = - & { - id: string; - description?: string; - files: json; - content?: string; - filename?: string; - }; - export type GistsStarParams = - & { - id: string; - }; - export type GistsUnstarParams = - & { - id: string; - }; - export type GistsForkParams = - & { - id: string; - }; - export type GistsDeleteParams = - & { - id: string; - }; - export type GistsGetForUserParams = - & { - username: string; - since?: date; - page?: number; - per_page?: number; - }; - export type GistsGetAllParams = - & { - since?: date; - page?: number; - per_page?: number; - }; - export type GistsGetPublicParams = - & { - since?: date; - }; - export type GistsGetStarredParams = - & { - since?: date; - }; - export type GistsGetRevisionParams = - & { - id: string; - sha: string; - }; - export type GistsGetCommitsParams = - & { - id: string; - }; - export type GistsCheckStarParams = - & { - id: string; - }; - export type GistsGetForksParams = - & { - id: string; - page?: number; - per_page?: number; - }; - export type GistsGetCommentsParams = - & { - gist_id: string; - }; - export type GistsGetCommentParams = - & { - gist_id: string; - id: string; - }; - export type GistsCreateCommentParams = - & { - gist_id: string; - body: string; - }; - export type GistsEditCommentParams = - & { - gist_id: string; - id: string; - body: string; - }; - export type GistsDeleteCommentParams = - & { - gist_id: string; - id: string; - }; - export type GitdataGetBlobParams = - & { - owner: string; - repo: string; - sha: string; - page?: number; - per_page?: number; - }; - export type GitdataCreateBlobParams = - & { - owner: string; - repo: string; - content: string; - encoding: string; - }; - export type GitdataGetCommitParams = - & { - owner: string; - repo: string; - sha: string; - }; - export type GitdataCreateCommitParams = - & { - owner: string; - repo: string; - message: string; - tree: string; - parents: string[]; - author?: json; - committer?: json; - }; - export type GitdataGetCommitSignatureVerificationParams = - & { - owner: string; - repo: string; - sha: string; - }; - export type GitdataGetReferenceParams = - & { - owner: string; - repo: string; - ref: string; - }; - export type GitdataGetReferencesParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type GitdataGetTagsParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type GitdataCreateReferenceParams = - & { - owner: string; - repo: string; - ref: string; - sha: string; - }; - export type GitdataUpdateReferenceParams = - & { - owner: string; - repo: string; - ref: string; - sha: string; - force?: boolean; - }; - export type GitdataDeleteReferenceParams = - & { - owner: string; - repo: string; - ref: string; - }; - export type GitdataGetTagParams = - & { - owner: string; - repo: string; - sha: string; - }; - export type GitdataCreateTagParams = - & { - owner: string; - repo: string; - tag: string; - message: string; - object: string; - type: string; - tagger: json; - }; - export type GitdataGetTagSignatureVerificationParams = - & { - owner: string; - repo: string; - sha: string; - }; - export type GitdataGetTreeParams = - & { - owner: string; - repo: string; - sha: string; - recursive?: boolean; - }; - export type GitdataCreateTreeParams = - & { - owner: string; - repo: string; - tree: json; - base_tree?: string; - }; - export type IntegrationsGetInstallationsParams = - & { - page?: number; - per_page?: number; - }; - export type IntegrationsCreateInstallationTokenParams = - & { - installation_id: string; - user_id?: string; - }; - export type IntegrationsGetInstallationRepositoriesParams = - & { - user_id?: string; - }; - export type IntegrationsAddRepoToInstallationParams = - & { - installation_id: string; - repository_id: string; - }; - export type IntegrationsRemoveRepoFromInstallationParams = - & { - installation_id: string; - repository_id: string; - }; - export type AppsGetForSlugParams = - & { - app_slug: string; - }; - export type AppsGetInstallationsParams = - & { - page?: number; - per_page?: number; - }; - export type AppsGetInstallationParams = - & { - installation_id: string; - }; - export type AppsCreateInstallationTokenParams = - & { - installation_id: string; - user_id?: string; - }; - export type AppsGetInstallationRepositoriesParams = - & { - user_id?: string; - }; - export type AppsAddRepoToInstallationParams = - & { - installation_id: string; - repository_id: string; - }; - export type AppsRemoveRepoFromInstallationParams = - & { - installation_id: string; - repository_id: string; - }; - export type AppsGetMarketplaceListingPlansParams = - & { - page?: number; - per_page?: number; - }; - export type AppsGetMarketplaceListingStubbedPlansParams = - & { - page?: number; - per_page?: number; - }; - export type AppsGetMarketplaceListingPlanAccountsParams = - & { - id: string; - page?: number; - per_page?: number; - }; - export type AppsGetMarketplaceListingStubbedPlanAccountsParams = - & { - id: string; - page?: number; - per_page?: number; - }; - export type AppsCheckMarketplaceListingAccountParams = - & { - id: string; - }; - export type AppsCheckMarketplaceListingStubbedAccountParams = - & { - id: string; - }; - export type IssuesGetParams = - & { - owner: string; - repo: string; - number: number; - }; - export type IssuesCreateParams = - & { - owner: string; - repo: string; - title: string; - body?: string; - assignee?: string; - milestone?: number; - labels?: string[]; - assignees?: string[]; - }; - export type IssuesEditParams = - & { - owner: string; - repo: string; - number: number; - title?: string; - body?: string; - assignee?: string; - state?: "open"|"closed"; - milestone?: number; - labels?: string[]; - assignees?: string[]; - }; - export type IssuesLockParams = - & { - owner: string; - repo: string; - number: number; - }; - export type IssuesUnlockParams = - & { - owner: string; - repo: string; - number: number; - }; - export type IssuesGetAllParams = - & { - filter?: "all"|"assigned"|"created"|"mentioned"|"subscribed"; - state?: "open"|"closed"|"all"; - labels?: string; - sort?: "created"|"updated"|"comments"; - direction?: "asc"|"desc"; - since?: date; - page?: number; - per_page?: number; - }; - export type IssuesGetForUserParams = - & { - filter?: "all"|"assigned"|"created"|"mentioned"|"subscribed"; - state?: "open"|"closed"|"all"; - labels?: string; - sort?: "created"|"updated"|"comments"; - direction?: "asc"|"desc"; - since?: date; - page?: number; - per_page?: number; - }; - export type IssuesGetForOrgParams = - & { - org: string; - filter?: "all"|"assigned"|"created"|"mentioned"|"subscribed"; - state?: "open"|"closed"|"all"; - labels?: string; - sort?: "created"|"updated"|"comments"; - direction?: "asc"|"desc"; - since?: date; - page?: number; - per_page?: number; - }; - export type IssuesGetForRepoParams = - & { - owner: string; - repo: string; - milestone?: string; - state?: "open"|"closed"|"all"; - assignee?: string; - creator?: string; - mentioned?: string; - labels?: string; - sort?: "created"|"updated"|"comments"; - direction?: "asc"|"desc"; - since?: date; - page?: number; - per_page?: number; - }; - export type IssuesGetAssigneesParams = - & { - owner: string; - repo: string; - }; - export type IssuesCheckAssigneeParams = - & { - owner: string; - repo: string; - assignee: string; - }; - export type IssuesAddAssigneesToIssueParams = - & { - owner: string; - repo: string; - number: number; - assignees: string[]; - }; - export type IssuesRemoveAssigneesFromIssueParams = - & { - owner: string; - repo: string; - number: number; - body: json; - }; - export type IssuesGetCommentsParams = - & { - owner: string; - repo: string; - number: number; - since?: date; - page?: number; - per_page?: number; - }; - export type IssuesGetCommentsForRepoParams = - & { - owner: string; - repo: string; - sort?: "created"|"updated"; - direction?: "asc"|"desc"; - since?: date; - page?: number; - per_page?: number; - }; - export type IssuesGetCommentParams = - & { - owner: string; - repo: string; - id: string; - }; - export type IssuesCreateCommentParams = - & { - owner: string; - repo: string; - number: number; - body: string; - }; - export type IssuesEditCommentParams = - & { - owner: string; - repo: string; - id: string; - body: string; - }; - export type IssuesDeleteCommentParams = - & { - owner: string; - repo: string; - id: string; - }; - export type IssuesGetEventsParams = - & { - owner: string; - repo: string; - issue_number: number; - page?: number; - per_page?: number; - }; - export type IssuesGetEventsForRepoParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type IssuesGetEventParams = - & { - owner: string; - repo: string; - id: string; - }; - export type IssuesGetLabelsParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type IssuesGetLabelParams = - & { - owner: string; - repo: string; - name: string; - }; - export type IssuesCreateLabelParams = - & { - owner: string; - repo: string; - name: string; - color: string; - }; - export type IssuesUpdateLabelParams = - & { - owner: string; - repo: string; - oldname: string; - name: string; - color: string; - }; - export type IssuesDeleteLabelParams = - & { - owner: string; - repo: string; - name: string; - }; - export type IssuesGetIssueLabelsParams = - & { - owner: string; - repo: string; - number: number; - }; - export type IssuesAddLabelsParams = - & { - owner: string; - repo: string; - number: number; - labels: string[]; - }; - export type IssuesRemoveLabelParams = - & { - owner: string; - repo: string; - number: number; - name: string; - }; - export type IssuesReplaceAllLabelsParams = - & { - owner: string; - repo: string; - number: number; - labels: string[]; - }; - export type IssuesRemoveAllLabelsParams = - & { - owner: string; - repo: string; - number: number; - }; - export type IssuesGetMilestoneLabelsParams = - & { - owner: string; - repo: string; - number: number; - }; - export type IssuesGetMilestonesParams = - & { - owner: string; - repo: string; - state?: "open"|"closed"|"all"; - sort?: "due_on"|"completeness"; - direction?: "asc"|"desc"; - page?: number; - per_page?: number; - }; - export type IssuesGetMilestoneParams = - & { - owner: string; - repo: string; - number: number; - }; - export type IssuesCreateMilestoneParams = - & { - owner: string; - repo: string; - title: string; - state?: "open"|"closed"|"all"; - description?: string; - due_on?: date; - }; - export type IssuesUpdateMilestoneParams = - & { - owner: string; - repo: string; - number: number; - title: string; - state?: "open"|"closed"|"all"; - description?: string; - due_on?: date; - }; - export type IssuesDeleteMilestoneParams = - & { - owner: string; - repo: string; - number: number; - }; - export type IssuesGetEventsTimelineParams = - & { - owner: string; - repo: string; - issue_number: number; - page?: number; - per_page?: number; - }; - export type MigrationsStartMigrationParams = - & { - org: string; - repositories: string[]; - lock_repositories?: boolean; - exclude_attachments?: boolean; - }; - export type MigrationsGetMigrationsParams = - & { - org: string; - page?: number; - per_page?: number; - }; - export type MigrationsGetMigrationStatusParams = - & { - org: string; - id: string; - }; - export type MigrationsGetMigrationArchiveLinkParams = - & { - org: string; - id: string; - }; - export type MigrationsDeleteMigrationArchiveParams = - & { - org: string; - id: string; - }; - export type MigrationsUnlockRepoLockedForMigrationParams = - & { - org: string; - id: string; - repo_name: string; - }; - export type MigrationsStartImportParams = - & { - owner: string; - repo: string; - vcs_url: string; - vcs?: "subversion"|"git"|"mercurial"|"tfvc"; - vcs_username?: string; - vcs_password?: string; - tfvc_project?: string; - }; - export type MigrationsGetImportProgressParams = - & { - owner: string; - repo: string; - }; - export type MigrationsUpdateImportParams = - & { - owner: string; - repo: string; - vcs_username?: string; - vcs_password?: string; - }; - export type MigrationsGetImportCommitAuthorsParams = - & { - owner: string; - repo: string; - since?: string; - }; - export type MigrationsMapImportCommitAuthorParams = - & { - owner: string; - repo: string; - author_id: string; - email?: string; - name?: string; - }; - export type MigrationsSetImportLfsPreferenceParams = - & { - owner: string; - name: string; - use_lfs: string; - }; - export type MigrationsGetLargeImportFilesParams = - & { - owner: string; - name: string; - }; - export type MigrationsCancelImportParams = - & { - owner: string; - repo: string; - }; - export type MiscGetCodeOfConductParams = - & { - key: string; - }; - export type MiscGetRepoCodeOfConductParams = - & { - owner: string; - repo: string; - }; - export type MiscGetGitignoreTemplateParams = - & { - name: string; - }; - export type MiscGetLicenseParams = - & { - license: string; - }; - export type MiscGetRepoLicenseParams = - & { - owner: string; - repo: string; - }; - export type MiscRenderMarkdownParams = - & { - text: string; - mode?: "markdown"|"gfm"; - context?: string; - }; - export type MiscRenderMarkdownRawParams = - & { - data: string; - }; - export type OrgsGetParams = - & { - org: string; - page?: number; - per_page?: number; - }; - export type OrgsUpdateParams = - & { - org: string; - billing_email?: string; - company?: string; - email?: string; - location?: string; - name?: string; - description?: string; - default_repository_permission?: "read"|"write"|"admin"|"none"; - members_can_create_repositories?: boolean; - }; - export type OrgsGetAllParams = - & { - since?: string; - page?: number; - per_page?: number; - }; - export type OrgsGetForUserParams = - & { - username: string; - page?: number; - per_page?: number; - }; - export type OrgsGetMembersParams = - & { - org: string; - filter?: "all"|"2fa_disabled"; - role?: "all"|"admin"|"member"; - page?: number; - per_page?: number; - }; - export type OrgsCheckMembershipParams = - & { - org: string; - username: string; - }; - export type OrgsRemoveMemberParams = - & { - org: string; - username: string; - }; - export type OrgsGetPublicMembersParams = - & { - org: string; - }; - export type OrgsCheckPublicMembershipParams = - & { - org: string; - username: string; - }; - export type OrgsPublicizeMembershipParams = - & { - org: string; - username: string; - }; - export type OrgsConcealMembershipParams = - & { - org: string; - username: string; - }; - export type OrgsGetOrgMembershipParams = - & { - org: string; - username: string; - }; - export type OrgsAddOrgMembershipParams = - & { - org: string; - username: string; - role: "admin"|"member"; - }; - export type OrgsRemoveOrgMembershipParams = - & { - org: string; - username: string; - }; - export type OrgsGetPendingOrgInvitesParams = - & { - org: string; - }; - export type OrgsGetOutsideCollaboratorsParams = - & { - org: string; - filter?: "all"|"2fa_disabled"; - page?: number; - per_page?: number; - }; - export type OrgsRemoveOutsideCollaboratorParams = - & { - org: string; - username: string; - }; - export type OrgsConvertMemberToOutsideCollaboratorParams = - & { - org: string; - username: string; - }; - export type OrgsGetTeamsParams = - & { - org: string; - page?: number; - per_page?: number; - }; - export type OrgsGetTeamParams = - & { - id: string; - }; - export type OrgsCreateTeamParams = - & { - org: string; - name: string; - description?: string; - maintainers?: string[]; - repo_names?: string[]; - privacy?: "secret"|"closed"; - parent_team_id?: string; - }; - export type OrgsEditTeamParams = - & { - id: string; - name: string; - description?: string; - privacy?: "secret"|"closed"; - parent_team_id?: string; - }; - export type OrgsDeleteTeamParams = - & { - id: string; - }; - export type OrgsGetTeamMembersParams = - & { - id: string; - role?: "member"|"maintainer"|"all"; - page?: number; - per_page?: number; - }; - export type OrgsGetChildTeamsParams = - & { - id: string; - page?: number; - per_page?: number; - }; - export type OrgsGetTeamMembershipParams = - & { - id: string; - username: string; - }; - export type OrgsAddTeamMembershipParams = - & { - id: string; - username: string; - role?: "member"|"maintainer"; - }; - export type OrgsRemoveTeamMembershipParams = - & { - id: string; - username: string; - }; - export type OrgsGetTeamReposParams = - & { - id: string; - page?: number; - per_page?: number; - }; - export type OrgsGetPendingTeamInvitesParams = - & { - id: string; - page?: number; - per_page?: number; - }; - export type OrgsCheckTeamRepoParams = - & { - id: string; - owner: string; - repo: string; - }; - export type OrgsAddTeamRepoParams = - & { - id: string; - org: string; - repo: string; - permission?: "pull"|"push"|"admin"; - }; - export type OrgsDeleteTeamRepoParams = - & { - id: string; - owner: string; - repo: string; - }; - export type OrgsGetHooksParams = - & { - org: string; - page?: number; - per_page?: number; - }; - export type OrgsGetHookParams = - & { - org: string; - id: string; - }; - export type OrgsCreateHookParams = - & { - org: string; - name: string; - config: json; - events?: string[]; - active?: boolean; - }; - export type OrgsEditHookParams = - & { - org: string; - id: string; - config: json; - events?: string[]; - active?: boolean; - }; - export type OrgsPingHookParams = - & { - org: string; - id: string; - }; - export type OrgsDeleteHookParams = - & { - org: string; - id: string; - }; - export type OrgsGetBlockedUsersParams = - & { - org: string; - page?: number; - per_page?: number; - }; - export type OrgsCheckBlockedUserParams = - & { - org: string; - username: string; - }; - export type OrgsBlockUserParams = - & { - org: string; - username: string; - }; - export type OrgsUnblockUserParams = - & { - org: string; - username: string; - }; - export type ProjectsGetRepoProjectsParams = - & { - owner: string; - repo: string; - state?: "open"|"closed"|"all"; - }; - export type ProjectsGetOrgProjectsParams = - & { - org: string; - state?: "open"|"closed"|"all"; - }; - export type ProjectsGetProjectParams = - & { - id: string; - }; - export type ProjectsCreateRepoProjectParams = - & { - owner: string; - repo: string; - name: string; - body?: string; - }; - export type ProjectsCreateOrgProjectParams = - & { - org: string; - name: string; - body?: string; - }; - export type ProjectsUpdateProjectParams = - & { - id: string; - name: string; - body?: string; - state?: "open"|"closed"|"all"; - }; - export type ProjectsDeleteProjectParams = - & { - id: string; - }; - export type ProjectsGetProjectCardsParams = - & { - column_id: string; - }; - export type ProjectsGetProjectCardParams = - & { - id: string; - }; - export type ProjectsCreateProjectCardParams = - & { - column_id: string; - note?: string; - content_id?: string; - content_type?: string; - }; - export type ProjectsUpdateProjectCardParams = - & { - id: string; - note?: string; - }; - export type ProjectsDeleteProjectCardParams = - & { - id: string; - }; - export type ProjectsMoveProjectCardParams = - & { - id: string; - position: string; - column_id?: string; - }; - export type ProjectsGetProjectColumnsParams = - & { - project_id: string; - }; - export type ProjectsGetProjectColumnParams = - & { - id: string; - }; - export type ProjectsCreateProjectColumnParams = - & { - project_id: string; - name: string; - }; - export type ProjectsUpdateProjectColumnParams = - & { - id: string; - name: string; - }; - export type ProjectsDeleteProjectColumnParams = - & { - id: string; - }; - export type ProjectsMoveProjectColumnParams = - & { - id: string; - position: string; - }; - export type PullRequestsGetParams = - & { - owner: string; - repo: string; - number: number; - }; - export type PullRequestsCreateParams = - & { - owner: string; - repo: string; - head: string; - base: string; - }; - export type PullRequestsUpdateParams = - & { - owner: string; - repo: string; - number: number; - title?: string; - body?: string; - state?: "open"|"closed"; - base?: string; - maintainer_can_modify?: boolean; - }; - export type PullRequestsMergeParams = - & { - owner: string; - repo: string; - number: number; - commit_title?: string; - commit_message?: string; - sha?: string; - merge_method?: "merge"|"squash"|"rebase"; - }; - export type PullRequestsGetAllParams = - & { - owner: string; - repo: string; - state?: "open"|"closed"|"all"; - head?: string; - base?: string; - sort?: "created"|"updated"|"popularity"|"long-running"; - direction?: "asc"|"desc"; - page?: number; - per_page?: number; - }; - export type PullRequestsCreateFromIssueParams = - & { - owner: string; - repo: string; - issue: number; - head: string; - base: string; - }; - export type PullRequestsGetCommitsParams = - & { - owner: string; - repo: string; - number: number; - page?: number; - per_page?: number; - }; - export type PullRequestsGetFilesParams = - & { - owner: string; - repo: string; - number: number; - page?: number; - per_page?: number; - }; - export type PullRequestsCheckMergedParams = - & { - owner: string; - repo: string; - number: number; - page?: number; - per_page?: number; - }; - export type PullRequestsGetReviewsParams = - & { - owner: string; - repo: string; - number: number; - page?: number; - per_page?: number; - }; - export type PullRequestsGetReviewParams = - & { - owner: string; - repo: string; - number: number; - id: string; - }; - export type PullRequestsDeletePendingReviewParams = - & { - owner: string; - repo: string; - number: number; - id: string; - }; - export type PullRequestsGetReviewCommentsParams = - & { - owner: string; - repo: string; - number: number; - id: string; - page?: number; - per_page?: number; - }; - export type PullRequestsCreateReviewParams = - & { - owner: string; - repo: string; - number: number; - commit_id?: string; - body?: string; - event?: "APPROVE"|"REQUEST_CHANGES"|"COMMENT"|"PENDING"; - comments?: string[]; - }; - export type PullRequestsSubmitReviewParams = - & { - owner: string; - repo: string; - number: number; - id: string; - body?: string; - event?: "APPROVE"|"REQUEST_CHANGES"|"COMMENT"|"PENDING"; - }; - export type PullRequestsDismissReviewParams = - & { - owner: string; - repo: string; - number: number; - id: string; - message?: string; - page?: number; - per_page?: number; - }; - export type PullRequestsGetCommentsParams = - & { - owner: string; - repo: string; - number: number; - page?: number; - per_page?: number; - }; - export type PullRequestsGetCommentsForRepoParams = - & { - owner: string; - repo: string; - sort?: "created"|"updated"; - direction?: "asc"|"desc"; - since?: date; - page?: number; - per_page?: number; - }; - export type PullRequestsGetCommentParams = - & { - owner: string; - repo: string; - id: string; - }; - export type PullRequestsCreateCommentParams = - & { - owner: string; - repo: string; - number: number; - body: string; - }; - export type PullRequestsCreateCommentReplyParams = - & { - owner: string; - repo: string; - number: number; - body: string; - in_reply_to: number; - }; - export type PullRequestsEditCommentParams = - & { - owner: string; - repo: string; - id: string; - body: string; - }; - export type PullRequestsDeleteCommentParams = - & { - owner: string; - repo: string; - id: string; - }; - export type PullRequestsGetReviewRequestsParams = - & { - owner: string; - repo: string; - number: number; - page?: number; - per_page?: number; - }; - export type PullRequestsCreateReviewRequestParams = - & { - owner: string; - repo: string; - number: number; - reviewers?: string[]; - team_reviewers?: string[]; - }; - export type PullRequestsDeleteReviewRequestParams = - & { - owner: string; - repo: string; - number: number; - reviewers?: string[]; - team_reviewers?: string[]; - }; - export type ReactionsDeleteParams = - & { - id: string; - }; - export type ReactionsGetForCommitCommentParams = - & { - owner: string; - repo: string; - id: string; - content?: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; - }; - export type ReactionsCreateForCommitCommentParams = - & { - owner: string; - repo: string; - id: string; - content: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; - }; - export type ReactionsGetForIssueParams = - & { - owner: string; - repo: string; - number: number; - content?: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; - }; - export type ReactionsCreateForIssueParams = - & { - owner: string; - repo: string; - number: number; - content: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; - }; - export type ReactionsGetForIssueCommentParams = - & { - owner: string; - repo: string; - id: string; - content?: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; - }; - export type ReactionsCreateForIssueCommentParams = - & { - owner: string; - repo: string; - id: string; - content: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; - }; - export type ReactionsGetForPullRequestReviewCommentParams = - & { - owner: string; - repo: string; - id: string; - content?: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; - }; - export type ReactionsCreateForPullRequestReviewCommentParams = - & { - owner: string; - repo: string; - id: string; - content: "+1"|"-1"|"laugh"|"confused"|"heart"|"hooray"; - }; - export type ReposCreateParams = - & { - name: string; - description?: string; - homepage?: string; - private?: boolean; - has_issues?: boolean; - has_projects?: boolean; - has_wiki?: boolean; - team_id?: number; - auto_init?: boolean; - gitignore_template?: string; - license_template?: string; - allow_squash_merge?: boolean; - allow_merge_commit?: boolean; - allow_rebase_merge?: boolean; - }; - export type ReposGetParams = - & { - owner: string; - repo: string; - }; - export type ReposEditParams = - & { - owner: string; - repo: string; - name: string; - description?: string; - homepage?: string; - private?: boolean; - has_issues?: boolean; - has_projects?: boolean; - has_wiki?: boolean; - default_branch?: string; - allow_squash_merge?: boolean; - allow_merge_commit?: boolean; - allow_rebase_merge?: boolean; - }; - export type ReposDeleteParams = - & { - owner: string; - repo: string; - }; - export type ReposForkParams = - & { - owner: string; - repo: string; - organization?: string; - }; - export type ReposMergeParams = - & { - owner: string; - repo: string; - base: string; - head: string; - commit_message?: string; - }; - export type ReposGetAllParams = - & { - visibility?: "all"|"public"|"private"; - affiliation?: string; - type?: "all"|"owner"|"public"|"private"|"member"; - sort?: "created"|"updated"|"pushed"|"full_name"; - direction?: "asc"|"desc"; - page?: number; - per_page?: number; - }; - export type ReposGetForUserParams = - & { - username: string; - type?: "all"|"owner"|"member"; - sort?: "created"|"updated"|"pushed"|"full_name"; - direction?: "asc"|"desc"; - page?: number; - per_page?: number; - }; - export type ReposGetForOrgParams = - & { - org: string; - type?: "all"|"public"|"private"|"forks"|"sources"|"member"; - page?: number; - per_page?: number; - }; - export type ReposGetPublicParams = - & { - since?: string; - page?: number; - per_page?: number; - }; - export type ReposCreateForOrgParams = - & { - org: string; - name: string; - description?: string; - homepage?: string; - private?: boolean; - has_issues?: boolean; - has_projects?: boolean; - has_wiki?: boolean; - team_id?: number; - auto_init?: boolean; - gitignore_template?: string; - license_template?: string; - allow_squash_merge?: boolean; - allow_merge_commit?: boolean; - allow_rebase_merge?: boolean; - }; - export type ReposGetByIdParams = - & { - id: string; - }; - export type ReposGetTopicsParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposReplaceTopicsParams = - & { - owner: string; - repo: string; - names: string[]; - }; - export type ReposGetContributorsParams = - & { - owner: string; - repo: string; - anon?: boolean; - page?: number; - per_page?: number; - }; - export type ReposGetLanguagesParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetTeamsParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetTagsParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetBranchesParams = - & { - owner: string; - repo: string; - protected?: boolean; - page?: number; - per_page?: number; - }; - export type ReposGetBranchParams = - & { - owner: string; - repo: string; - branch: string; - page?: number; - per_page?: number; - }; - export type ReposGetBranchProtectionParams = - & { - owner: string; - repo: string; - branch: string; - page?: number; - per_page?: number; - }; - export type ReposUpdateBranchProtectionParams = - & { - owner: string; - repo: string; - branch: string; - required_status_checks: json; - required_pull_request_reviews: json; - dismissal_restrictions?: json; - restrictions: json; - enforce_admins: boolean; - page?: number; - per_page?: number; - }; - export type ReposRemoveBranchProtectionParams = - & { - owner: string; - repo: string; - branch: string; - }; - export type ReposGetProtectedBranchRequiredStatusChecksParams = - & { - owner: string; - repo: string; - branch: string; - page?: number; - per_page?: number; - }; - export type ReposUpdateProtectedBranchRequiredStatusChecksParams = - & { - owner: string; - repo: string; - branch: string; - strict?: boolean; - contexts?: string[]; - }; - export type ReposRemoveProtectedBranchRequiredStatusChecksParams = - & { - owner: string; - repo: string; - branch: string; - }; - export type ReposGetProtectedBranchRequiredStatusChecksContextsParams = - & { - owner: string; - repo: string; - branch: string; - page?: number; - per_page?: number; - }; - export type ReposReplaceProtectedBranchRequiredStatusChecksContextsParams = - & { - owner: string; - repo: string; - branch: string; - contexts: string[]; - }; - export type ReposAddProtectedBranchRequiredStatusChecksContextsParams = - & { - owner: string; - repo: string; - branch: string; - contexts: string[]; - }; - export type ReposRemoveProtectedBranchRequiredStatusChecksContextsParams = - & { - owner: string; - repo: string; - branch: string; - contexts: string[]; - }; - export type ReposGetProtectedBranchPullRequestReviewEnforcementParams = - & { - owner: string; - repo: string; - branch: string; - page?: number; - per_page?: number; - }; - export type ReposUpdateProtectedBranchPullRequestReviewEnforcementParams = - & { - owner: string; - repo: string; - branch: string; - dismissal_restrictions?: json; - dismiss_stale_reviews?: boolean; - require_code_owner_reviews?: boolean; - }; - export type ReposRemoveProtectedBranchPullRequestReviewEnforcementParams = - & { - owner: string; - repo: string; - branch: string; - }; - export type ReposGetProtectedBranchAdminEnforcementParams = - & { - owner: string; - repo: string; - branch: string; - page?: number; - per_page?: number; - }; - export type ReposAddProtectedBranchAdminEnforcementParams = - & { - owner: string; - repo: string; - branch: string; - page?: number; - per_page?: number; - }; - export type ReposRemoveProtectedBranchAdminEnforcementParams = - & { - owner: string; - repo: string; - branch: string; - }; - export type ReposGetProtectedBranchRestrictionsParams = - & { - owner: string; - repo: string; - branch: string; - page?: number; - per_page?: number; - }; - export type ReposRemoveProtectedBranchRestrictionsParams = - & { - owner: string; - repo: string; - branch: string; - }; - export type ReposGetProtectedBranchTeamRestrictionsParams = - & { - owner: string; - repo: string; - branch: string; - page?: number; - per_page?: number; - }; - export type ReposReplaceProtectedBranchTeamRestrictionsParams = - & { - owner: string; - repo: string; - branch: string; - teams: string[]; - }; - export type ReposAddProtectedBranchTeamRestrictionsParams = - & { - owner: string; - repo: string; - branch: string; - teams: string[]; - }; - export type ReposRemoveProtectedBranchTeamRestrictionsParams = - & { - owner: string; - repo: string; - branch: string; - teams: string[]; - }; - export type ReposGetProtectedBranchUserRestrictionsParams = - & { - owner: string; - repo: string; - branch: string; - page?: number; - per_page?: number; - }; - export type ReposReplaceProtectedBranchUserRestrictionsParams = - & { - owner: string; - repo: string; - branch: string; - users: string[]; - }; - export type ReposAddProtectedBranchUserRestrictionsParams = - & { - owner: string; - repo: string; - branch: string; - users: string[]; - }; - export type ReposRemoveProtectedBranchUserRestrictionsParams = - & { - owner: string; - repo: string; - branch: string; - users: string[]; - }; - export type ReposGetCollaboratorsParams = - & { - owner: string; - repo: string; - affiliation?: "outside"|"all"|"direct"; - page?: number; - per_page?: number; - }; - export type ReposCheckCollaboratorParams = - & { - owner: string; - repo: string; - username: string; - }; - export type ReposReviewUserPermissionLevelParams = - & { - owner: string; - repo: string; - username: string; - }; - export type ReposAddCollaboratorParams = - & { - owner: string; - repo: string; - username: string; - permission?: "pull"|"push"|"admin"; - }; - export type ReposRemoveCollaboratorParams = - & { - owner: string; - repo: string; - username: string; - }; - export type ReposGetAllCommitCommentsParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetCommitCommentsParams = - & { - owner: string; - repo: string; - ref: string; - page?: number; - per_page?: number; - }; - export type ReposCreateCommitCommentParams = - & { - owner: string; - repo: string; - sha: string; - body: string; - path?: string; - position?: number; - }; - export type ReposGetCommitCommentParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposUpdateCommitCommentParams = - & { - owner: string; - repo: string; - id: string; - body: string; - }; - export type ReposDeleteCommitCommentParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposGetCommunityProfileMetricsParams = - & { - owner: string; - name: string; - }; - export type ReposGetCommitsParams = - & { - owner: string; - repo: string; - sha?: string; - path?: string; - author?: string; - since?: date; - until?: date; - page?: number; - per_page?: number; - }; - export type ReposGetCommitParams = - & { - owner: string; - repo: string; - sha: string; - }; - export type ReposGetShaOfCommitRefParams = - & { - owner: string; - repo: string; - ref: string; - }; - export type ReposCompareCommitsParams = - & { - owner: string; - repo: string; - base: string; - head: string; - }; - export type ReposGetReadmeParams = - & { - owner: string; - repo: string; - ref?: string; - }; - export type ReposGetContentParams = - & { - owner: string; - repo: string; - path: string; - ref?: string; - }; - export type ReposCreateFileParams = - & { - owner: string; - repo: string; - path: string; - message: string; - content: string; - branch?: string; - committer?: json; - author?: json; - }; - export type ReposUpdateFileParams = - & { - owner: string; - repo: string; - path: string; - message: string; - content: string; - sha: string; - branch?: string; - committer?: json; - author?: json; - }; - export type ReposDeleteFileParams = - & { - owner: string; - repo: string; - path: string; - message: string; - sha: string; - branch?: string; - committer?: json; - author?: json; - }; - export type ReposGetArchiveLinkParams = - & { - owner: string; - repo: string; - archive_format: "tarball"|"zipball"; - ref?: string; - }; - export type ReposGetDeployKeysParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetDeployKeyParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposAddDeployKeyParams = - & { - owner: string; - repo: string; - title: string; - key: string; - read_only?: boolean; - }; - export type ReposDeleteDeployKeyParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposGetDeploymentsParams = - & { - owner: string; - repo: string; - sha?: string; - ref?: string; - task?: string; - environment?: string; - page?: number; - per_page?: number; - }; - export type ReposGetDeploymentParams = - & { - owner: string; - repo: string; - deployment_id: string; - }; - export type ReposCreateDeploymentParams = - & { - owner: string; - repo: string; - ref: string; - task?: string; - auto_merge?: boolean; - required_contexts?: string[]; - payload?: string; - environment?: string; - description?: string; - transient_environment?: boolean; - production_environment?: boolean; - }; - export type ReposGetDeploymentStatusesParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposGetDeploymentStatusParams = - & { - owner: string; - repo: string; - id: string; - status_id: string; - }; - export type ReposCreateDeploymentStatusParams = - & { - owner: string; - repo: string; - id: string; - state?: string; - target_url?: string; - log_url?: string; - description?: string; - environment_url?: string; - auto_inactive?: boolean; - }; - export type ReposGetDownloadsParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetDownloadParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposDeleteDownloadParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposGetForksParams = - & { - owner: string; - repo: string; - sort?: "newest"|"oldest"|"stargazers"; - page?: number; - per_page?: number; - }; - export type ReposGetInvitesParams = - & { - owner: string; - repo: string; - }; - export type ReposDeleteInviteParams = - & { - owner: string; - repo: string; - invitation_id: string; - }; - export type ReposUpdateInviteParams = - & { - owner: string; - repo: string; - invitation_id: string; - permissions?: "read"|"write"|"admin"; - }; - export type ReposGetPagesParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposRequestPageBuildParams = - & { - owner: string; - repo: string; - }; - export type ReposGetPagesBuildsParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetLatestPagesBuildParams = - & { - owner: string; - repo: string; - }; - export type ReposGetPagesBuildParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposGetReleasesParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetReleaseParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposGetLatestReleaseParams = - & { - owner: string; - repo: string; - }; - export type ReposGetReleaseByTagParams = - & { - owner: string; - repo: string; - tag: string; - }; - export type ReposCreateReleaseParams = - & { - owner: string; - repo: string; - tag_name: string; - target_commitish?: string; - name?: string; - body?: string; - draft?: boolean; - prerelease?: boolean; - }; - export type ReposEditReleaseParams = - & { - owner: string; - repo: string; - id: string; - tag_name: string; - target_commitish?: string; - name?: string; - body?: string; - draft?: boolean; - prerelease?: boolean; - }; - export type ReposDeleteReleaseParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposGetAssetsParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposUploadAssetParams = - & { - url: string; - file: string | object; - contentType: string; - contentLength: number; - name: string; - label?: string; - }; - export type ReposGetAssetParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposEditAssetParams = - & { - owner: string; - repo: string; - id: string; - name: string; - label?: string; - }; - export type ReposDeleteAssetParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposGetStatsContributorsParams = - & { - owner: string; - repo: string; - }; - export type ReposGetStatsCommitActivityParams = - & { - owner: string; - repo: string; - }; - export type ReposGetStatsCodeFrequencyParams = - & { - owner: string; - repo: string; - }; - export type ReposGetStatsParticipationParams = - & { - owner: string; - repo: string; - }; - export type ReposGetStatsPunchCardParams = - & { - owner: string; - repo: string; - }; - export type ReposCreateStatusParams = - & { - owner: string; - repo: string; - sha: string; - state: "pending"|"success"|"error"|"failure"; - target_url?: string; - description?: string; - context?: string; - }; - export type ReposGetStatusesParams = - & { - owner: string; - repo: string; - ref: string; - page?: number; - per_page?: number; - }; - export type ReposGetCombinedStatusForRefParams = - & { - owner: string; - repo: string; - ref: string; - page?: number; - per_page?: number; - }; - export type ReposGetReferrersParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetPathsParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetViewsParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetClonesParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetHooksParams = - & { - owner: string; - repo: string; - page?: number; - per_page?: number; - }; - export type ReposGetHookParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposCreateHookParams = - & { - owner: string; - repo: string; - name: string; - config: json; - events?: string[]; - active?: boolean; - }; - export type ReposEditHookParams = - & { - owner: string; - repo: string; - id: string; - name: string; - config: json; - events?: string[]; - add_events?: string[]; - remove_events?: string[]; - active?: boolean; - }; - export type ReposTestHookParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposPingHookParams = - & { - owner: string; - repo: string; - id: string; - }; - export type ReposDeleteHookParams = - & { - owner: string; - repo: string; - id: string; - }; - export type SearchReposParams = - & { - q: string; - sort?: "stars"|"forks"|"updated"; - order?: "asc"|"desc"; - page?: number; - per_page?: number; - }; - export type SearchCodeParams = - & { - q: string; - sort?: "indexed"; - order?: "asc"|"desc"; - page?: number; - per_page?: number; - }; - export type SearchCommitsParams = - & { - q: string; - sort?: "author-date"|"committer-date"; - order?: "asc"|"desc"; - page?: number; - per_page?: number; - }; - export type SearchIssuesParams = - & { - q: string; - sort?: "comments"|"created"|"updated"; - order?: "asc"|"desc"; - page?: number; - per_page?: number; - }; - export type SearchUsersParams = - & { - q: string; - sort?: "followers"|"repositories"|"joined"; - order?: "asc"|"desc"; - page?: number; - per_page?: number; - }; - export type SearchEmailParams = - & { - email: string; - }; - export type UsersUpdateParams = - & { - name?: string; - email?: string; - blog?: string; - company?: string; - location?: string; - hireable?: boolean; - bio?: string; - }; - export type UsersPromoteParams = - & { - username: string; - }; - export type UsersDemoteParams = - & { - username: string; - }; - export type UsersSuspendParams = - & { - username: string; - }; - export type UsersUnsuspendParams = - & { - username: string; - }; - export type UsersGetForUserParams = - & { - username: string; - }; - export type UsersGetByIdParams = - & { - id: string; - }; - export type UsersGetAllParams = - & { - since?: number; - }; - export type UsersGetOrgsParams = - & { - page?: number; - per_page?: number; - }; - export type UsersGetOrgMembershipsParams = - & { - state?: "active"|"pending"; - }; - export type UsersGetOrgMembershipParams = - & { - org: string; - }; - export type UsersEditOrgMembershipParams = - & { - org: string; - state: "active"; - }; - export type UsersGetTeamsParams = - & { - page?: number; - per_page?: number; - }; - export type UsersGetEmailsParams = - & { - page?: number; - per_page?: number; - }; - export type UsersGetPublicEmailsParams = - & { - page?: number; - per_page?: number; - }; - export type UsersAddEmailsParams = - & { - emails: string[]; - }; - export type UsersDeleteEmailsParams = - & { - emails: string[]; - }; - export type UsersGetFollowersForUserParams = - & { - username: string; - page?: number; - per_page?: number; - }; - export type UsersGetFollowersParams = - & { - page?: number; - per_page?: number; - }; - export type UsersGetFollowingForUserParams = - & { - username: string; - page?: number; - per_page?: number; - }; - export type UsersGetFollowingParams = - & { - page?: number; - per_page?: number; - }; - export type UsersCheckFollowingParams = - & { - username: string; - }; - export type UsersCheckIfOneFollowersOtherParams = - & { - username: string; - target_user: string; - }; - export type UsersFollowUserParams = - & { - username: string; - }; - export type UsersUnfollowUserParams = - & { - username: string; - }; - export type UsersGetKeysForUserParams = - & { - username: string; - page?: number; - per_page?: number; - }; - export type UsersGetKeysParams = - & { - page?: number; - per_page?: number; - }; - export type UsersGetKeyParams = - & { - id: string; - }; - export type UsersCreateKeyParams = - & { - title: string; - key: string; - }; - export type UsersDeleteKeyParams = - & { - id: string; - }; - export type UsersGetGpgKeysForUserParams = - & { - username: string; - page?: number; - per_page?: number; - }; - export type UsersGetGpgKeysParams = - & { - page?: number; - per_page?: number; - }; - export type UsersGetGpgKeyParams = - & { - id: string; - }; - export type UsersCreateGpgKeyParams = - & { - armored_public_key: string; - }; - export type UsersDeleteGpgKeyParams = - & { - id: string; - }; - export type UsersCheckBlockedUserParams = - & { - username: string; - }; - export type UsersBlockUserParams = - & { - username: string; - }; - export type UsersUnblockUserParams = - & { - username: string; - }; - export type UsersAcceptRepoInviteParams = - & { - invitation_id: string; - }; - export type UsersDeclineRepoInviteParams = - & { - invitation_id: string; - }; - export type UsersGetInstallationsParams = - & { - page?: number; - per_page?: number; - }; - export type UsersGetInstallationReposParams = - & { - installation_id: string; - page?: number; - per_page?: number; - }; - export type UsersAddRepoToInstallationParams = - & { - installation_id: string; - repository_id: string; - }; - export type UsersRemoveRepoFromInstallationParams = - & { - installation_id: string; - repository_id: string; - }; - export type UsersGetMarketplacePurchasesParams = - & { - page?: number; - per_page?: number; - }; - export type UsersGetMarketplaceStubbedPurchasesParams = - & { - page?: number; - per_page?: number; - }; - export type EnterpriseStatsParams = - & { - type: "issues"|"hooks"|"milestones"|"orgs"|"comments"|"pages"|"users"|"gists"|"pulls"|"repos"|"all"; - }; - export type EnterpriseUpdateLdapForUserParams = - & { - username: string; - ldap_dn: string; - }; - export type EnterpriseSyncLdapForUserParams = - & { - username: string; - }; - export type EnterpriseUpdateLdapForTeamParams = - & { - team_id: number; - ldap_dn: string; - }; - export type EnterpriseSyncLdapForTeamParams = - & { - team_id: number; - }; - export type EnterpriseGetPreReceiveEnvironmentParams = - & { - id: string; - }; - export type EnterpriseCreatePreReceiveEnvironmentParams = - & { - name: string; - image_url: string; - }; - export type EnterpriseEditPreReceiveEnvironmentParams = - & { - id: string; - name: string; - image_url: string; - }; - export type EnterpriseDeletePreReceiveEnvironmentParams = - & { - id: string; - }; - export type EnterpriseGetPreReceiveEnvironmentDownloadStatusParams = - & { - id: string; - }; - export type EnterpriseTriggerPreReceiveEnvironmentDownloadParams = - & { - id: string; - }; - export type EnterpriseGetPreReceiveHookParams = - & { - id: string; - }; - export type EnterpriseCreatePreReceiveHookParams = - & { - name: string; - script: string; - script_repository: json; - environment: json; - enforcement?: string; - allow_downstream_configuration?: boolean; - }; - export type EnterpriseEditPreReceiveHookParams = - & { - id: string; - hook: json; - }; - export type EnterpriseDeletePreReceiveHookParams = - & { - id: string; - }; - export type EnterpriseQueueIndexingJobParams = - & { - target: string; - }; - export type EnterpriseCreateOrgParams = - & { - login: string; - admin: string; - profile_name?: string; - }; -} - -declare class Github { - constructor(options?: Github.Options); - authenticate(auth: Github.Auth): void; - hasNextPage(link: Github.Link): string | undefined; - hasPreviousPage(link: Github.Link): string | undefined; - hasLastPage(link: Github.Link): string | undefined; - hasFirstPage(link: Github.Link): string | undefined; - - getNextPage(link: Github.Link, callback?: Github.Callback): Promise; - getNextPage(link: Github.Link, headers?: {[header: string]: any}, callback?: Github.Callback): Promise; - - getPreviousPage(link: Github.Link, callback?: Github.Callback): Promise; - getPreviousPage(link: Github.Link, headers?: {[header: string]: any}, callback?: Github.Callback): Promise; - - getLastPage(link: Github.Link, callback?: Github.Callback): Promise; - getLastPage(link: Github.Link, headers?: {[header: string]: any}, callback?: Github.Callback): Promise; - - getFirstPage(link: Github.Link, callback?: Github.Callback): Promise; - getFirstPage(link: Github.Link, headers?: {[header: string]: any}, callback?: Github.Callback): Promise; - - authorization: { - get(params: Github.AuthorizationGetParams, callback?: Github.Callback): Promise; - create(params: Github.AuthorizationCreateParams, callback?: Github.Callback): Promise; - update(params: Github.AuthorizationUpdateParams, callback?: Github.Callback): Promise; - delete(params: Github.AuthorizationDeleteParams, callback?: Github.Callback): Promise; - check(params: Github.AuthorizationCheckParams, callback?: Github.Callback): Promise; - reset(params: Github.AuthorizationResetParams, callback?: Github.Callback): Promise; - revoke(params: Github.AuthorizationRevokeParams, callback?: Github.Callback): Promise; - getGrants(params: Github.AuthorizationGetGrantsParams, callback?: Github.Callback): Promise; - getGrant(params: Github.AuthorizationGetGrantParams, callback?: Github.Callback): Promise; - deleteGrant(params: Github.AuthorizationDeleteGrantParams, callback?: Github.Callback): Promise; - getAll(params: Github.AuthorizationGetAllParams, callback?: Github.Callback): Promise; - getOrCreateAuthorizationForApp(params: Github.AuthorizationGetOrCreateAuthorizationForAppParams, callback?: Github.Callback): Promise; - getOrCreateAuthorizationForAppAndFingerprint(params: Github.AuthorizationGetOrCreateAuthorizationForAppAndFingerprintParams, callback?: Github.Callback): Promise; - revokeGrant(params: Github.AuthorizationRevokeGrantParams, callback?: Github.Callback): Promise; - }; - activity: { - getEvents(params: Github.ActivityGetEventsParams, callback?: Github.Callback): Promise; - getEventsForRepo(params: Github.ActivityGetEventsForRepoParams, callback?: Github.Callback): Promise; - getEventsForRepoIssues(params: Github.ActivityGetEventsForRepoIssuesParams, callback?: Github.Callback): Promise; - getEventsForRepoNetwork(params: Github.ActivityGetEventsForRepoNetworkParams, callback?: Github.Callback): Promise; - getEventsForOrg(params: Github.ActivityGetEventsForOrgParams, callback?: Github.Callback): Promise; - getEventsReceived(params: Github.ActivityGetEventsReceivedParams, callback?: Github.Callback): Promise; - getEventsReceivedPublic(params: Github.ActivityGetEventsReceivedPublicParams, callback?: Github.Callback): Promise; - getEventsForUser(params: Github.ActivityGetEventsForUserParams, callback?: Github.Callback): Promise; - getEventsForUserPublic(params: Github.ActivityGetEventsForUserPublicParams, callback?: Github.Callback): Promise; - getEventsForUserOrg(params: Github.ActivityGetEventsForUserOrgParams, callback?: Github.Callback): Promise; - getFeeds(params: Github.EmptyParams, callback?: Github.Callback): Promise; - getNotifications(params: Github.ActivityGetNotificationsParams, callback?: Github.Callback): Promise; - getNotificationsForUser(params: Github.ActivityGetNotificationsForUserParams, callback?: Github.Callback): Promise; - markNotificationsAsRead(params: Github.ActivityMarkNotificationsAsReadParams, callback?: Github.Callback): Promise; - markNotificationsAsReadForRepo(params: Github.ActivityMarkNotificationsAsReadForRepoParams, callback?: Github.Callback): Promise; - getNotificationThread(params: Github.ActivityGetNotificationThreadParams, callback?: Github.Callback): Promise; - markNotificationThreadAsRead(params: Github.ActivityMarkNotificationThreadAsReadParams, callback?: Github.Callback): Promise; - checkNotificationThreadSubscription(params: Github.ActivityCheckNotificationThreadSubscriptionParams, callback?: Github.Callback): Promise; - setNotificationThreadSubscription(params: Github.ActivitySetNotificationThreadSubscriptionParams, callback?: Github.Callback): Promise; - deleteNotificationThreadSubscription(params: Github.ActivityDeleteNotificationThreadSubscriptionParams, callback?: Github.Callback): Promise; - getStargazersForRepo(params: Github.ActivityGetStargazersForRepoParams, callback?: Github.Callback): Promise; - getStarredReposForUser(params: Github.ActivityGetStarredReposForUserParams, callback?: Github.Callback): Promise; - getStarredRepos(params: Github.ActivityGetStarredReposParams, callback?: Github.Callback): Promise; - checkStarringRepo(params: Github.ActivityCheckStarringRepoParams, callback?: Github.Callback): Promise; - starRepo(params: Github.ActivityStarRepoParams, callback?: Github.Callback): Promise; - unstarRepo(params: Github.ActivityUnstarRepoParams, callback?: Github.Callback): Promise; - getWatchersForRepo(params: Github.ActivityGetWatchersForRepoParams, callback?: Github.Callback): Promise; - getWatchedReposForUser(params: Github.ActivityGetWatchedReposForUserParams, callback?: Github.Callback): Promise; - getWatchedRepos(params: Github.ActivityGetWatchedReposParams, callback?: Github.Callback): Promise; - getRepoSubscription(params: Github.ActivityGetRepoSubscriptionParams, callback?: Github.Callback): Promise; - setRepoSubscription(params: Github.ActivitySetRepoSubscriptionParams, callback?: Github.Callback): Promise; - unwatchRepo(params: Github.ActivityUnwatchRepoParams, callback?: Github.Callback): Promise; - }; - gists: { - get(params: Github.GistsGetParams, callback?: Github.Callback): Promise; - create(params: Github.GistsCreateParams, callback?: Github.Callback): Promise; - edit(params: Github.GistsEditParams, callback?: Github.Callback): Promise; - star(params: Github.GistsStarParams, callback?: Github.Callback): Promise; - unstar(params: Github.GistsUnstarParams, callback?: Github.Callback): Promise; - fork(params: Github.GistsForkParams, callback?: Github.Callback): Promise; - delete(params: Github.GistsDeleteParams, callback?: Github.Callback): Promise; - getForUser(params: Github.GistsGetForUserParams, callback?: Github.Callback): Promise; - getAll(params: Github.GistsGetAllParams, callback?: Github.Callback): Promise; - getPublic(params: Github.GistsGetPublicParams, callback?: Github.Callback): Promise; - getStarred(params: Github.GistsGetStarredParams, callback?: Github.Callback): Promise; - getRevision(params: Github.GistsGetRevisionParams, callback?: Github.Callback): Promise; - getCommits(params: Github.GistsGetCommitsParams, callback?: Github.Callback): Promise; - checkStar(params: Github.GistsCheckStarParams, callback?: Github.Callback): Promise; - getForks(params: Github.GistsGetForksParams, callback?: Github.Callback): Promise; - getComments(params: Github.GistsGetCommentsParams, callback?: Github.Callback): Promise; - getComment(params: Github.GistsGetCommentParams, callback?: Github.Callback): Promise; - createComment(params: Github.GistsCreateCommentParams, callback?: Github.Callback): Promise; - editComment(params: Github.GistsEditCommentParams, callback?: Github.Callback): Promise; - deleteComment(params: Github.GistsDeleteCommentParams, callback?: Github.Callback): Promise; - }; - gitdata: { - getBlob(params: Github.GitdataGetBlobParams, callback?: Github.Callback): Promise; - createBlob(params: Github.GitdataCreateBlobParams, callback?: Github.Callback): Promise; - getCommit(params: Github.GitdataGetCommitParams, callback?: Github.Callback): Promise; - createCommit(params: Github.GitdataCreateCommitParams, callback?: Github.Callback): Promise; - getCommitSignatureVerification(params: Github.GitdataGetCommitSignatureVerificationParams, callback?: Github.Callback): Promise; - getReference(params: Github.GitdataGetReferenceParams, callback?: Github.Callback): Promise; - getReferences(params: Github.GitdataGetReferencesParams, callback?: Github.Callback): Promise; - getTags(params: Github.GitdataGetTagsParams, callback?: Github.Callback): Promise; - createReference(params: Github.GitdataCreateReferenceParams, callback?: Github.Callback): Promise; - updateReference(params: Github.GitdataUpdateReferenceParams, callback?: Github.Callback): Promise; - deleteReference(params: Github.GitdataDeleteReferenceParams, callback?: Github.Callback): Promise; - getTag(params: Github.GitdataGetTagParams, callback?: Github.Callback): Promise; - createTag(params: Github.GitdataCreateTagParams, callback?: Github.Callback): Promise; - getTagSignatureVerification(params: Github.GitdataGetTagSignatureVerificationParams, callback?: Github.Callback): Promise; - getTree(params: Github.GitdataGetTreeParams, callback?: Github.Callback): Promise; - createTree(params: Github.GitdataCreateTreeParams, callback?: Github.Callback): Promise; - }; - integrations: { - getInstallations(params: Github.IntegrationsGetInstallationsParams, callback?: Github.Callback): Promise; - createInstallationToken(params: Github.IntegrationsCreateInstallationTokenParams, callback?: Github.Callback): Promise; - getInstallationRepositories(params: Github.IntegrationsGetInstallationRepositoriesParams, callback?: Github.Callback): Promise; - addRepoToInstallation(params: Github.IntegrationsAddRepoToInstallationParams, callback?: Github.Callback): Promise; - removeRepoFromInstallation(params: Github.IntegrationsRemoveRepoFromInstallationParams, callback?: Github.Callback): Promise; - }; - apps: { - get(params: Github.EmptyParams, callback?: Github.Callback): Promise; - getForSlug(params: Github.AppsGetForSlugParams, callback?: Github.Callback): Promise; - getInstallations(params: Github.AppsGetInstallationsParams, callback?: Github.Callback): Promise; - getInstallation(params: Github.AppsGetInstallationParams, callback?: Github.Callback): Promise; - createInstallationToken(params: Github.AppsCreateInstallationTokenParams, callback?: Github.Callback): Promise; - getInstallationRepositories(params: Github.AppsGetInstallationRepositoriesParams, callback?: Github.Callback): Promise; - addRepoToInstallation(params: Github.AppsAddRepoToInstallationParams, callback?: Github.Callback): Promise; - removeRepoFromInstallation(params: Github.AppsRemoveRepoFromInstallationParams, callback?: Github.Callback): Promise; - getMarketplaceListingPlans(params: Github.AppsGetMarketplaceListingPlansParams, callback?: Github.Callback): Promise; - getMarketplaceListingStubbedPlans(params: Github.AppsGetMarketplaceListingStubbedPlansParams, callback?: Github.Callback): Promise; - getMarketplaceListingPlanAccounts(params: Github.AppsGetMarketplaceListingPlanAccountsParams, callback?: Github.Callback): Promise; - getMarketplaceListingStubbedPlanAccounts(params: Github.AppsGetMarketplaceListingStubbedPlanAccountsParams, callback?: Github.Callback): Promise; - checkMarketplaceListingAccount(params: Github.AppsCheckMarketplaceListingAccountParams, callback?: Github.Callback): Promise; - checkMarketplaceListingStubbedAccount(params: Github.AppsCheckMarketplaceListingStubbedAccountParams, callback?: Github.Callback): Promise; - }; - issues: { - get(params: Github.IssuesGetParams, callback?: Github.Callback): Promise; - create(params: Github.IssuesCreateParams, callback?: Github.Callback): Promise; - edit(params: Github.IssuesEditParams, callback?: Github.Callback): Promise; - lock(params: Github.IssuesLockParams, callback?: Github.Callback): Promise; - unlock(params: Github.IssuesUnlockParams, callback?: Github.Callback): Promise; - getAll(params: Github.IssuesGetAllParams, callback?: Github.Callback): Promise; - getForUser(params: Github.IssuesGetForUserParams, callback?: Github.Callback): Promise; - getForOrg(params: Github.IssuesGetForOrgParams, callback?: Github.Callback): Promise; - getForRepo(params: Github.IssuesGetForRepoParams, callback?: Github.Callback): Promise; - getAssignees(params: Github.IssuesGetAssigneesParams, callback?: Github.Callback): Promise; - checkAssignee(params: Github.IssuesCheckAssigneeParams, callback?: Github.Callback): Promise; - addAssigneesToIssue(params: Github.IssuesAddAssigneesToIssueParams, callback?: Github.Callback): Promise; - removeAssigneesFromIssue(params: Github.IssuesRemoveAssigneesFromIssueParams, callback?: Github.Callback): Promise; - getComments(params: Github.IssuesGetCommentsParams, callback?: Github.Callback): Promise; - getCommentsForRepo(params: Github.IssuesGetCommentsForRepoParams, callback?: Github.Callback): Promise; - getComment(params: Github.IssuesGetCommentParams, callback?: Github.Callback): Promise; - createComment(params: Github.IssuesCreateCommentParams, callback?: Github.Callback): Promise; - editComment(params: Github.IssuesEditCommentParams, callback?: Github.Callback): Promise; - deleteComment(params: Github.IssuesDeleteCommentParams, callback?: Github.Callback): Promise; - getEvents(params: Github.IssuesGetEventsParams, callback?: Github.Callback): Promise; - getEventsForRepo(params: Github.IssuesGetEventsForRepoParams, callback?: Github.Callback): Promise; - getEvent(params: Github.IssuesGetEventParams, callback?: Github.Callback): Promise; - getLabels(params: Github.IssuesGetLabelsParams, callback?: Github.Callback): Promise; - getLabel(params: Github.IssuesGetLabelParams, callback?: Github.Callback): Promise; - createLabel(params: Github.IssuesCreateLabelParams, callback?: Github.Callback): Promise; - updateLabel(params: Github.IssuesUpdateLabelParams, callback?: Github.Callback): Promise; - deleteLabel(params: Github.IssuesDeleteLabelParams, callback?: Github.Callback): Promise; - getIssueLabels(params: Github.IssuesGetIssueLabelsParams, callback?: Github.Callback): Promise; - addLabels(params: Github.IssuesAddLabelsParams, callback?: Github.Callback): Promise; - removeLabel(params: Github.IssuesRemoveLabelParams, callback?: Github.Callback): Promise; - replaceAllLabels(params: Github.IssuesReplaceAllLabelsParams, callback?: Github.Callback): Promise; - removeAllLabels(params: Github.IssuesRemoveAllLabelsParams, callback?: Github.Callback): Promise; - getMilestoneLabels(params: Github.IssuesGetMilestoneLabelsParams, callback?: Github.Callback): Promise; - getMilestones(params: Github.IssuesGetMilestonesParams, callback?: Github.Callback): Promise; - getMilestone(params: Github.IssuesGetMilestoneParams, callback?: Github.Callback): Promise; - createMilestone(params: Github.IssuesCreateMilestoneParams, callback?: Github.Callback): Promise; - updateMilestone(params: Github.IssuesUpdateMilestoneParams, callback?: Github.Callback): Promise; - deleteMilestone(params: Github.IssuesDeleteMilestoneParams, callback?: Github.Callback): Promise; - getEventsTimeline(params: Github.IssuesGetEventsTimelineParams, callback?: Github.Callback): Promise; - }; - migrations: { - startMigration(params: Github.MigrationsStartMigrationParams, callback?: Github.Callback): Promise; - getMigrations(params: Github.MigrationsGetMigrationsParams, callback?: Github.Callback): Promise; - getMigrationStatus(params: Github.MigrationsGetMigrationStatusParams, callback?: Github.Callback): Promise; - getMigrationArchiveLink(params: Github.MigrationsGetMigrationArchiveLinkParams, callback?: Github.Callback): Promise; - deleteMigrationArchive(params: Github.MigrationsDeleteMigrationArchiveParams, callback?: Github.Callback): Promise; - unlockRepoLockedForMigration(params: Github.MigrationsUnlockRepoLockedForMigrationParams, callback?: Github.Callback): Promise; - startImport(params: Github.MigrationsStartImportParams, callback?: Github.Callback): Promise; - getImportProgress(params: Github.MigrationsGetImportProgressParams, callback?: Github.Callback): Promise; - updateImport(params: Github.MigrationsUpdateImportParams, callback?: Github.Callback): Promise; - getImportCommitAuthors(params: Github.MigrationsGetImportCommitAuthorsParams, callback?: Github.Callback): Promise; - mapImportCommitAuthor(params: Github.MigrationsMapImportCommitAuthorParams, callback?: Github.Callback): Promise; - setImportLfsPreference(params: Github.MigrationsSetImportLfsPreferenceParams, callback?: Github.Callback): Promise; - getLargeImportFiles(params: Github.MigrationsGetLargeImportFilesParams, callback?: Github.Callback): Promise; - cancelImport(params: Github.MigrationsCancelImportParams, callback?: Github.Callback): Promise; - }; - misc: { - getCodesOfConduct(params: Github.EmptyParams, callback?: Github.Callback): Promise; - getCodeOfConduct(params: Github.MiscGetCodeOfConductParams, callback?: Github.Callback): Promise; - getRepoCodeOfConduct(params: Github.MiscGetRepoCodeOfConductParams, callback?: Github.Callback): Promise; - getEmojis(params: Github.EmptyParams, callback?: Github.Callback): Promise; - getGitignoreTemplates(params: Github.EmptyParams, callback?: Github.Callback): Promise; - getGitignoreTemplate(params: Github.MiscGetGitignoreTemplateParams, callback?: Github.Callback): Promise; - getLicenses(params: Github.EmptyParams, callback?: Github.Callback): Promise; - getLicense(params: Github.MiscGetLicenseParams, callback?: Github.Callback): Promise; - getRepoLicense(params: Github.MiscGetRepoLicenseParams, callback?: Github.Callback): Promise; - renderMarkdown(params: Github.MiscRenderMarkdownParams, callback?: Github.Callback): Promise; - renderMarkdownRaw(params: Github.MiscRenderMarkdownRawParams, callback?: Github.Callback): Promise; - getMeta(params: Github.EmptyParams, callback?: Github.Callback): Promise; - getRateLimit(params: Github.EmptyParams, callback?: Github.Callback): Promise; - }; - orgs: { - get(params: Github.OrgsGetParams, callback?: Github.Callback): Promise; - update(params: Github.OrgsUpdateParams, callback?: Github.Callback): Promise; - getAll(params: Github.OrgsGetAllParams, callback?: Github.Callback): Promise; - getForUser(params: Github.OrgsGetForUserParams, callback?: Github.Callback): Promise; - getMembers(params: Github.OrgsGetMembersParams, callback?: Github.Callback): Promise; - checkMembership(params: Github.OrgsCheckMembershipParams, callback?: Github.Callback): Promise; - removeMember(params: Github.OrgsRemoveMemberParams, callback?: Github.Callback): Promise; - getPublicMembers(params: Github.OrgsGetPublicMembersParams, callback?: Github.Callback): Promise; - checkPublicMembership(params: Github.OrgsCheckPublicMembershipParams, callback?: Github.Callback): Promise; - publicizeMembership(params: Github.OrgsPublicizeMembershipParams, callback?: Github.Callback): Promise; - concealMembership(params: Github.OrgsConcealMembershipParams, callback?: Github.Callback): Promise; - getOrgMembership(params: Github.OrgsGetOrgMembershipParams, callback?: Github.Callback): Promise; - addOrgMembership(params: Github.OrgsAddOrgMembershipParams, callback?: Github.Callback): Promise; - removeOrgMembership(params: Github.OrgsRemoveOrgMembershipParams, callback?: Github.Callback): Promise; - getPendingOrgInvites(params: Github.OrgsGetPendingOrgInvitesParams, callback?: Github.Callback): Promise; - getOutsideCollaborators(params: Github.OrgsGetOutsideCollaboratorsParams, callback?: Github.Callback): Promise; - removeOutsideCollaborator(params: Github.OrgsRemoveOutsideCollaboratorParams, callback?: Github.Callback): Promise; - convertMemberToOutsideCollaborator(params: Github.OrgsConvertMemberToOutsideCollaboratorParams, callback?: Github.Callback): Promise; - getTeams(params: Github.OrgsGetTeamsParams, callback?: Github.Callback): Promise; - getTeam(params: Github.OrgsGetTeamParams, callback?: Github.Callback): Promise; - createTeam(params: Github.OrgsCreateTeamParams, callback?: Github.Callback): Promise; - editTeam(params: Github.OrgsEditTeamParams, callback?: Github.Callback): Promise; - deleteTeam(params: Github.OrgsDeleteTeamParams, callback?: Github.Callback): Promise; - getTeamMembers(params: Github.OrgsGetTeamMembersParams, callback?: Github.Callback): Promise; - getChildTeams(params: Github.OrgsGetChildTeamsParams, callback?: Github.Callback): Promise; - getTeamMembership(params: Github.OrgsGetTeamMembershipParams, callback?: Github.Callback): Promise; - addTeamMembership(params: Github.OrgsAddTeamMembershipParams, callback?: Github.Callback): Promise; - removeTeamMembership(params: Github.OrgsRemoveTeamMembershipParams, callback?: Github.Callback): Promise; - getTeamRepos(params: Github.OrgsGetTeamReposParams, callback?: Github.Callback): Promise; - getPendingTeamInvites(params: Github.OrgsGetPendingTeamInvitesParams, callback?: Github.Callback): Promise; - checkTeamRepo(params: Github.OrgsCheckTeamRepoParams, callback?: Github.Callback): Promise; - addTeamRepo(params: Github.OrgsAddTeamRepoParams, callback?: Github.Callback): Promise; - deleteTeamRepo(params: Github.OrgsDeleteTeamRepoParams, callback?: Github.Callback): Promise; - getHooks(params: Github.OrgsGetHooksParams, callback?: Github.Callback): Promise; - getHook(params: Github.OrgsGetHookParams, callback?: Github.Callback): Promise; - createHook(params: Github.OrgsCreateHookParams, callback?: Github.Callback): Promise; - editHook(params: Github.OrgsEditHookParams, callback?: Github.Callback): Promise; - pingHook(params: Github.OrgsPingHookParams, callback?: Github.Callback): Promise; - deleteHook(params: Github.OrgsDeleteHookParams, callback?: Github.Callback): Promise; - getBlockedUsers(params: Github.OrgsGetBlockedUsersParams, callback?: Github.Callback): Promise; - checkBlockedUser(params: Github.OrgsCheckBlockedUserParams, callback?: Github.Callback): Promise; - blockUser(params: Github.OrgsBlockUserParams, callback?: Github.Callback): Promise; - unblockUser(params: Github.OrgsUnblockUserParams, callback?: Github.Callback): Promise; - }; - projects: { - getRepoProjects(params: Github.ProjectsGetRepoProjectsParams, callback?: Github.Callback): Promise; - getOrgProjects(params: Github.ProjectsGetOrgProjectsParams, callback?: Github.Callback): Promise; - getProject(params: Github.ProjectsGetProjectParams, callback?: Github.Callback): Promise; - createRepoProject(params: Github.ProjectsCreateRepoProjectParams, callback?: Github.Callback): Promise; - createOrgProject(params: Github.ProjectsCreateOrgProjectParams, callback?: Github.Callback): Promise; - updateProject(params: Github.ProjectsUpdateProjectParams, callback?: Github.Callback): Promise; - deleteProject(params: Github.ProjectsDeleteProjectParams, callback?: Github.Callback): Promise; - getProjectCards(params: Github.ProjectsGetProjectCardsParams, callback?: Github.Callback): Promise; - getProjectCard(params: Github.ProjectsGetProjectCardParams, callback?: Github.Callback): Promise; - createProjectCard(params: Github.ProjectsCreateProjectCardParams, callback?: Github.Callback): Promise; - updateProjectCard(params: Github.ProjectsUpdateProjectCardParams, callback?: Github.Callback): Promise; - deleteProjectCard(params: Github.ProjectsDeleteProjectCardParams, callback?: Github.Callback): Promise; - moveProjectCard(params: Github.ProjectsMoveProjectCardParams, callback?: Github.Callback): Promise; - getProjectColumns(params: Github.ProjectsGetProjectColumnsParams, callback?: Github.Callback): Promise; - getProjectColumn(params: Github.ProjectsGetProjectColumnParams, callback?: Github.Callback): Promise; - createProjectColumn(params: Github.ProjectsCreateProjectColumnParams, callback?: Github.Callback): Promise; - updateProjectColumn(params: Github.ProjectsUpdateProjectColumnParams, callback?: Github.Callback): Promise; - deleteProjectColumn(params: Github.ProjectsDeleteProjectColumnParams, callback?: Github.Callback): Promise; - moveProjectColumn(params: Github.ProjectsMoveProjectColumnParams, callback?: Github.Callback): Promise; - }; - pullRequests: { - get(params: Github.PullRequestsGetParams, callback?: Github.Callback): Promise; - create(params: Github.PullRequestsCreateParams, callback?: Github.Callback): Promise; - update(params: Github.PullRequestsUpdateParams, callback?: Github.Callback): Promise; - merge(params: Github.PullRequestsMergeParams, callback?: Github.Callback): Promise; - getAll(params: Github.PullRequestsGetAllParams, callback?: Github.Callback): Promise; - createFromIssue(params: Github.PullRequestsCreateFromIssueParams, callback?: Github.Callback): Promise; - getCommits(params: Github.PullRequestsGetCommitsParams, callback?: Github.Callback): Promise; - getFiles(params: Github.PullRequestsGetFilesParams, callback?: Github.Callback): Promise; - checkMerged(params: Github.PullRequestsCheckMergedParams, callback?: Github.Callback): Promise; - getReviews(params: Github.PullRequestsGetReviewsParams, callback?: Github.Callback): Promise; - getReview(params: Github.PullRequestsGetReviewParams, callback?: Github.Callback): Promise; - deletePendingReview(params: Github.PullRequestsDeletePendingReviewParams, callback?: Github.Callback): Promise; - getReviewComments(params: Github.PullRequestsGetReviewCommentsParams, callback?: Github.Callback): Promise; - createReview(params: Github.PullRequestsCreateReviewParams, callback?: Github.Callback): Promise; - submitReview(params: Github.PullRequestsSubmitReviewParams, callback?: Github.Callback): Promise; - dismissReview(params: Github.PullRequestsDismissReviewParams, callback?: Github.Callback): Promise; - getComments(params: Github.PullRequestsGetCommentsParams, callback?: Github.Callback): Promise; - getCommentsForRepo(params: Github.PullRequestsGetCommentsForRepoParams, callback?: Github.Callback): Promise; - getComment(params: Github.PullRequestsGetCommentParams, callback?: Github.Callback): Promise; - createComment(params: Github.PullRequestsCreateCommentParams, callback?: Github.Callback): Promise; - createCommentReply(params: Github.PullRequestsCreateCommentReplyParams, callback?: Github.Callback): Promise; - editComment(params: Github.PullRequestsEditCommentParams, callback?: Github.Callback): Promise; - deleteComment(params: Github.PullRequestsDeleteCommentParams, callback?: Github.Callback): Promise; - getReviewRequests(params: Github.PullRequestsGetReviewRequestsParams, callback?: Github.Callback): Promise; - createReviewRequest(params: Github.PullRequestsCreateReviewRequestParams, callback?: Github.Callback): Promise; - deleteReviewRequest(params: Github.PullRequestsDeleteReviewRequestParams, callback?: Github.Callback): Promise; - }; - reactions: { - delete(params: Github.ReactionsDeleteParams, callback?: Github.Callback): Promise; - getForCommitComment(params: Github.ReactionsGetForCommitCommentParams, callback?: Github.Callback): Promise; - createForCommitComment(params: Github.ReactionsCreateForCommitCommentParams, callback?: Github.Callback): Promise; - getForIssue(params: Github.ReactionsGetForIssueParams, callback?: Github.Callback): Promise; - createForIssue(params: Github.ReactionsCreateForIssueParams, callback?: Github.Callback): Promise; - getForIssueComment(params: Github.ReactionsGetForIssueCommentParams, callback?: Github.Callback): Promise; - createForIssueComment(params: Github.ReactionsCreateForIssueCommentParams, callback?: Github.Callback): Promise; - getForPullRequestReviewComment(params: Github.ReactionsGetForPullRequestReviewCommentParams, callback?: Github.Callback): Promise; - createForPullRequestReviewComment(params: Github.ReactionsCreateForPullRequestReviewCommentParams, callback?: Github.Callback): Promise; - }; - repos: { - create(params: Github.ReposCreateParams, callback?: Github.Callback): Promise; - get(params: Github.ReposGetParams, callback?: Github.Callback): Promise; - edit(params: Github.ReposEditParams, callback?: Github.Callback): Promise; - delete(params: Github.ReposDeleteParams, callback?: Github.Callback): Promise; - fork(params: Github.ReposForkParams, callback?: Github.Callback): Promise; - merge(params: Github.ReposMergeParams, callback?: Github.Callback): Promise; - getAll(params: Github.ReposGetAllParams, callback?: Github.Callback): Promise; - getForUser(params: Github.ReposGetForUserParams, callback?: Github.Callback): Promise; - getForOrg(params: Github.ReposGetForOrgParams, callback?: Github.Callback): Promise; - getPublic(params: Github.ReposGetPublicParams, callback?: Github.Callback): Promise; - createForOrg(params: Github.ReposCreateForOrgParams, callback?: Github.Callback): Promise; - getById(params: Github.ReposGetByIdParams, callback?: Github.Callback): Promise; - getTopics(params: Github.ReposGetTopicsParams, callback?: Github.Callback): Promise; - replaceTopics(params: Github.ReposReplaceTopicsParams, callback?: Github.Callback): Promise; - getContributors(params: Github.ReposGetContributorsParams, callback?: Github.Callback): Promise; - getLanguages(params: Github.ReposGetLanguagesParams, callback?: Github.Callback): Promise; - getTeams(params: Github.ReposGetTeamsParams, callback?: Github.Callback): Promise; - getTags(params: Github.ReposGetTagsParams, callback?: Github.Callback): Promise; - getBranches(params: Github.ReposGetBranchesParams, callback?: Github.Callback): Promise; - getBranch(params: Github.ReposGetBranchParams, callback?: Github.Callback): Promise; - getBranchProtection(params: Github.ReposGetBranchProtectionParams, callback?: Github.Callback): Promise; - updateBranchProtection(params: Github.ReposUpdateBranchProtectionParams, callback?: Github.Callback): Promise; - removeBranchProtection(params: Github.ReposRemoveBranchProtectionParams, callback?: Github.Callback): Promise; - getProtectedBranchRequiredStatusChecks(params: Github.ReposGetProtectedBranchRequiredStatusChecksParams, callback?: Github.Callback): Promise; - updateProtectedBranchRequiredStatusChecks(params: Github.ReposUpdateProtectedBranchRequiredStatusChecksParams, callback?: Github.Callback): Promise; - removeProtectedBranchRequiredStatusChecks(params: Github.ReposRemoveProtectedBranchRequiredStatusChecksParams, callback?: Github.Callback): Promise; - getProtectedBranchRequiredStatusChecksContexts(params: Github.ReposGetProtectedBranchRequiredStatusChecksContextsParams, callback?: Github.Callback): Promise; - replaceProtectedBranchRequiredStatusChecksContexts(params: Github.ReposReplaceProtectedBranchRequiredStatusChecksContextsParams, callback?: Github.Callback): Promise; - addProtectedBranchRequiredStatusChecksContexts(params: Github.ReposAddProtectedBranchRequiredStatusChecksContextsParams, callback?: Github.Callback): Promise; - removeProtectedBranchRequiredStatusChecksContexts(params: Github.ReposRemoveProtectedBranchRequiredStatusChecksContextsParams, callback?: Github.Callback): Promise; - getProtectedBranchPullRequestReviewEnforcement(params: Github.ReposGetProtectedBranchPullRequestReviewEnforcementParams, callback?: Github.Callback): Promise; - updateProtectedBranchPullRequestReviewEnforcement(params: Github.ReposUpdateProtectedBranchPullRequestReviewEnforcementParams, callback?: Github.Callback): Promise; - removeProtectedBranchPullRequestReviewEnforcement(params: Github.ReposRemoveProtectedBranchPullRequestReviewEnforcementParams, callback?: Github.Callback): Promise; - getProtectedBranchAdminEnforcement(params: Github.ReposGetProtectedBranchAdminEnforcementParams, callback?: Github.Callback): Promise; - addProtectedBranchAdminEnforcement(params: Github.ReposAddProtectedBranchAdminEnforcementParams, callback?: Github.Callback): Promise; - removeProtectedBranchAdminEnforcement(params: Github.ReposRemoveProtectedBranchAdminEnforcementParams, callback?: Github.Callback): Promise; - getProtectedBranchRestrictions(params: Github.ReposGetProtectedBranchRestrictionsParams, callback?: Github.Callback): Promise; - removeProtectedBranchRestrictions(params: Github.ReposRemoveProtectedBranchRestrictionsParams, callback?: Github.Callback): Promise; - getProtectedBranchTeamRestrictions(params: Github.ReposGetProtectedBranchTeamRestrictionsParams, callback?: Github.Callback): Promise; - replaceProtectedBranchTeamRestrictions(params: Github.ReposReplaceProtectedBranchTeamRestrictionsParams, callback?: Github.Callback): Promise; - addProtectedBranchTeamRestrictions(params: Github.ReposAddProtectedBranchTeamRestrictionsParams, callback?: Github.Callback): Promise; - removeProtectedBranchTeamRestrictions(params: Github.ReposRemoveProtectedBranchTeamRestrictionsParams, callback?: Github.Callback): Promise; - getProtectedBranchUserRestrictions(params: Github.ReposGetProtectedBranchUserRestrictionsParams, callback?: Github.Callback): Promise; - replaceProtectedBranchUserRestrictions(params: Github.ReposReplaceProtectedBranchUserRestrictionsParams, callback?: Github.Callback): Promise; - addProtectedBranchUserRestrictions(params: Github.ReposAddProtectedBranchUserRestrictionsParams, callback?: Github.Callback): Promise; - removeProtectedBranchUserRestrictions(params: Github.ReposRemoveProtectedBranchUserRestrictionsParams, callback?: Github.Callback): Promise; - getCollaborators(params: Github.ReposGetCollaboratorsParams, callback?: Github.Callback): Promise; - checkCollaborator(params: Github.ReposCheckCollaboratorParams, callback?: Github.Callback): Promise; - reviewUserPermissionLevel(params: Github.ReposReviewUserPermissionLevelParams, callback?: Github.Callback): Promise; - addCollaborator(params: Github.ReposAddCollaboratorParams, callback?: Github.Callback): Promise; - removeCollaborator(params: Github.ReposRemoveCollaboratorParams, callback?: Github.Callback): Promise; - getAllCommitComments(params: Github.ReposGetAllCommitCommentsParams, callback?: Github.Callback): Promise; - getCommitComments(params: Github.ReposGetCommitCommentsParams, callback?: Github.Callback): Promise; - createCommitComment(params: Github.ReposCreateCommitCommentParams, callback?: Github.Callback): Promise; - getCommitComment(params: Github.ReposGetCommitCommentParams, callback?: Github.Callback): Promise; - updateCommitComment(params: Github.ReposUpdateCommitCommentParams, callback?: Github.Callback): Promise; - deleteCommitComment(params: Github.ReposDeleteCommitCommentParams, callback?: Github.Callback): Promise; - getCommunityProfileMetrics(params: Github.ReposGetCommunityProfileMetricsParams, callback?: Github.Callback): Promise; - getCommits(params: Github.ReposGetCommitsParams, callback?: Github.Callback): Promise; - getCommit(params: Github.ReposGetCommitParams, callback?: Github.Callback): Promise; - getShaOfCommitRef(params: Github.ReposGetShaOfCommitRefParams, callback?: Github.Callback): Promise; - compareCommits(params: Github.ReposCompareCommitsParams, callback?: Github.Callback): Promise; - getReadme(params: Github.ReposGetReadmeParams, callback?: Github.Callback): Promise; - getContent(params: Github.ReposGetContentParams, callback?: Github.Callback): Promise; - createFile(params: Github.ReposCreateFileParams, callback?: Github.Callback): Promise; - updateFile(params: Github.ReposUpdateFileParams, callback?: Github.Callback): Promise; - deleteFile(params: Github.ReposDeleteFileParams, callback?: Github.Callback): Promise; - getArchiveLink(params: Github.ReposGetArchiveLinkParams, callback?: Github.Callback): Promise; - getDeployKeys(params: Github.ReposGetDeployKeysParams, callback?: Github.Callback): Promise; - getDeployKey(params: Github.ReposGetDeployKeyParams, callback?: Github.Callback): Promise; - addDeployKey(params: Github.ReposAddDeployKeyParams, callback?: Github.Callback): Promise; - deleteDeployKey(params: Github.ReposDeleteDeployKeyParams, callback?: Github.Callback): Promise; - getDeployments(params: Github.ReposGetDeploymentsParams, callback?: Github.Callback): Promise; - getDeployment(params: Github.ReposGetDeploymentParams, callback?: Github.Callback): Promise; - createDeployment(params: Github.ReposCreateDeploymentParams, callback?: Github.Callback): Promise; - getDeploymentStatuses(params: Github.ReposGetDeploymentStatusesParams, callback?: Github.Callback): Promise; - getDeploymentStatus(params: Github.ReposGetDeploymentStatusParams, callback?: Github.Callback): Promise; - createDeploymentStatus(params: Github.ReposCreateDeploymentStatusParams, callback?: Github.Callback): Promise; - getDownloads(params: Github.ReposGetDownloadsParams, callback?: Github.Callback): Promise; - getDownload(params: Github.ReposGetDownloadParams, callback?: Github.Callback): Promise; - deleteDownload(params: Github.ReposDeleteDownloadParams, callback?: Github.Callback): Promise; - getForks(params: Github.ReposGetForksParams, callback?: Github.Callback): Promise; - getInvites(params: Github.ReposGetInvitesParams, callback?: Github.Callback): Promise; - deleteInvite(params: Github.ReposDeleteInviteParams, callback?: Github.Callback): Promise; - updateInvite(params: Github.ReposUpdateInviteParams, callback?: Github.Callback): Promise; - getPages(params: Github.ReposGetPagesParams, callback?: Github.Callback): Promise; - requestPageBuild(params: Github.ReposRequestPageBuildParams, callback?: Github.Callback): Promise; - getPagesBuilds(params: Github.ReposGetPagesBuildsParams, callback?: Github.Callback): Promise; - getLatestPagesBuild(params: Github.ReposGetLatestPagesBuildParams, callback?: Github.Callback): Promise; - getPagesBuild(params: Github.ReposGetPagesBuildParams, callback?: Github.Callback): Promise; - getReleases(params: Github.ReposGetReleasesParams, callback?: Github.Callback): Promise; - getRelease(params: Github.ReposGetReleaseParams, callback?: Github.Callback): Promise; - getLatestRelease(params: Github.ReposGetLatestReleaseParams, callback?: Github.Callback): Promise; - getReleaseByTag(params: Github.ReposGetReleaseByTagParams, callback?: Github.Callback): Promise; - createRelease(params: Github.ReposCreateReleaseParams, callback?: Github.Callback): Promise; - editRelease(params: Github.ReposEditReleaseParams, callback?: Github.Callback): Promise; - deleteRelease(params: Github.ReposDeleteReleaseParams, callback?: Github.Callback): Promise; - getAssets(params: Github.ReposGetAssetsParams, callback?: Github.Callback): Promise; - uploadAsset(params: Github.ReposUploadAssetParams, callback?: Github.Callback): Promise; - getAsset(params: Github.ReposGetAssetParams, callback?: Github.Callback): Promise; - editAsset(params: Github.ReposEditAssetParams, callback?: Github.Callback): Promise; - deleteAsset(params: Github.ReposDeleteAssetParams, callback?: Github.Callback): Promise; - getStatsContributors(params: Github.ReposGetStatsContributorsParams, callback?: Github.Callback): Promise; - getStatsCommitActivity(params: Github.ReposGetStatsCommitActivityParams, callback?: Github.Callback): Promise; - getStatsCodeFrequency(params: Github.ReposGetStatsCodeFrequencyParams, callback?: Github.Callback): Promise; - getStatsParticipation(params: Github.ReposGetStatsParticipationParams, callback?: Github.Callback): Promise; - getStatsPunchCard(params: Github.ReposGetStatsPunchCardParams, callback?: Github.Callback): Promise; - createStatus(params: Github.ReposCreateStatusParams, callback?: Github.Callback): Promise; - getStatuses(params: Github.ReposGetStatusesParams, callback?: Github.Callback): Promise; - getCombinedStatusForRef(params: Github.ReposGetCombinedStatusForRefParams, callback?: Github.Callback): Promise; - getReferrers(params: Github.ReposGetReferrersParams, callback?: Github.Callback): Promise; - getPaths(params: Github.ReposGetPathsParams, callback?: Github.Callback): Promise; - getViews(params: Github.ReposGetViewsParams, callback?: Github.Callback): Promise; - getClones(params: Github.ReposGetClonesParams, callback?: Github.Callback): Promise; - getHooks(params: Github.ReposGetHooksParams, callback?: Github.Callback): Promise; - getHook(params: Github.ReposGetHookParams, callback?: Github.Callback): Promise; - createHook(params: Github.ReposCreateHookParams, callback?: Github.Callback): Promise; - editHook(params: Github.ReposEditHookParams, callback?: Github.Callback): Promise; - testHook(params: Github.ReposTestHookParams, callback?: Github.Callback): Promise; - pingHook(params: Github.ReposPingHookParams, callback?: Github.Callback): Promise; - deleteHook(params: Github.ReposDeleteHookParams, callback?: Github.Callback): Promise; - }; - search: { - repos(params: Github.SearchReposParams, callback?: Github.Callback): Promise; - code(params: Github.SearchCodeParams, callback?: Github.Callback): Promise; - commits(params: Github.SearchCommitsParams, callback?: Github.Callback): Promise; - issues(params: Github.SearchIssuesParams, callback?: Github.Callback): Promise; - users(params: Github.SearchUsersParams, callback?: Github.Callback): Promise; - email(params: Github.SearchEmailParams, callback?: Github.Callback): Promise; - }; - users: { - get(params: Github.EmptyParams, callback?: Github.Callback): Promise; - update(params: Github.UsersUpdateParams, callback?: Github.Callback): Promise; - promote(params: Github.UsersPromoteParams, callback?: Github.Callback): Promise; - demote(params: Github.UsersDemoteParams, callback?: Github.Callback): Promise; - suspend(params: Github.UsersSuspendParams, callback?: Github.Callback): Promise; - unsuspend(params: Github.UsersUnsuspendParams, callback?: Github.Callback): Promise; - getForUser(params: Github.UsersGetForUserParams, callback?: Github.Callback): Promise; - getById(params: Github.UsersGetByIdParams, callback?: Github.Callback): Promise; - getAll(params: Github.UsersGetAllParams, callback?: Github.Callback): Promise; - getOrgs(params: Github.UsersGetOrgsParams, callback?: Github.Callback): Promise; - getOrgMemberships(params: Github.UsersGetOrgMembershipsParams, callback?: Github.Callback): Promise; - getOrgMembership(params: Github.UsersGetOrgMembershipParams, callback?: Github.Callback): Promise; - editOrgMembership(params: Github.UsersEditOrgMembershipParams, callback?: Github.Callback): Promise; - getTeams(params: Github.UsersGetTeamsParams, callback?: Github.Callback): Promise; - getEmails(params: Github.UsersGetEmailsParams, callback?: Github.Callback): Promise; - getPublicEmails(params: Github.UsersGetPublicEmailsParams, callback?: Github.Callback): Promise; - addEmails(params: Github.UsersAddEmailsParams, callback?: Github.Callback): Promise; - deleteEmails(params: Github.UsersDeleteEmailsParams, callback?: Github.Callback): Promise; - togglePrimaryEmailVisibility(params: Github.EmptyParams, callback?: Github.Callback): Promise; - getFollowersForUser(params: Github.UsersGetFollowersForUserParams, callback?: Github.Callback): Promise; - getFollowers(params: Github.UsersGetFollowersParams, callback?: Github.Callback): Promise; - getFollowingForUser(params: Github.UsersGetFollowingForUserParams, callback?: Github.Callback): Promise; - getFollowing(params: Github.UsersGetFollowingParams, callback?: Github.Callback): Promise; - checkFollowing(params: Github.UsersCheckFollowingParams, callback?: Github.Callback): Promise; - checkIfOneFollowersOther(params: Github.UsersCheckIfOneFollowersOtherParams, callback?: Github.Callback): Promise; - followUser(params: Github.UsersFollowUserParams, callback?: Github.Callback): Promise; - unfollowUser(params: Github.UsersUnfollowUserParams, callback?: Github.Callback): Promise; - getKeysForUser(params: Github.UsersGetKeysForUserParams, callback?: Github.Callback): Promise; - getKeys(params: Github.UsersGetKeysParams, callback?: Github.Callback): Promise; - getKey(params: Github.UsersGetKeyParams, callback?: Github.Callback): Promise; - createKey(params: Github.UsersCreateKeyParams, callback?: Github.Callback): Promise; - deleteKey(params: Github.UsersDeleteKeyParams, callback?: Github.Callback): Promise; - getGpgKeysForUser(params: Github.UsersGetGpgKeysForUserParams, callback?: Github.Callback): Promise; - getGpgKeys(params: Github.UsersGetGpgKeysParams, callback?: Github.Callback): Promise; - getGpgKey(params: Github.UsersGetGpgKeyParams, callback?: Github.Callback): Promise; - createGpgKey(params: Github.UsersCreateGpgKeyParams, callback?: Github.Callback): Promise; - deleteGpgKey(params: Github.UsersDeleteGpgKeyParams, callback?: Github.Callback): Promise; - getBlockedUsers(params: Github.EmptyParams, callback?: Github.Callback): Promise; - checkBlockedUser(params: Github.UsersCheckBlockedUserParams, callback?: Github.Callback): Promise; - blockUser(params: Github.UsersBlockUserParams, callback?: Github.Callback): Promise; - unblockUser(params: Github.UsersUnblockUserParams, callback?: Github.Callback): Promise; - getRepoInvites(params: Github.EmptyParams, callback?: Github.Callback): Promise; - acceptRepoInvite(params: Github.UsersAcceptRepoInviteParams, callback?: Github.Callback): Promise; - declineRepoInvite(params: Github.UsersDeclineRepoInviteParams, callback?: Github.Callback): Promise; - getInstallations(params: Github.UsersGetInstallationsParams, callback?: Github.Callback): Promise; - getInstallationRepos(params: Github.UsersGetInstallationReposParams, callback?: Github.Callback): Promise; - addRepoToInstallation(params: Github.UsersAddRepoToInstallationParams, callback?: Github.Callback): Promise; - removeRepoFromInstallation(params: Github.UsersRemoveRepoFromInstallationParams, callback?: Github.Callback): Promise; - getMarketplacePurchases(params: Github.UsersGetMarketplacePurchasesParams, callback?: Github.Callback): Promise; - getMarketplaceStubbedPurchases(params: Github.UsersGetMarketplaceStubbedPurchasesParams, callback?: Github.Callback): Promise; - }; - enterprise: { - stats(params: Github.EnterpriseStatsParams, callback?: Github.Callback): Promise; - updateLdapForUser(params: Github.EnterpriseUpdateLdapForUserParams, callback?: Github.Callback): Promise; - syncLdapForUser(params: Github.EnterpriseSyncLdapForUserParams, callback?: Github.Callback): Promise; - updateLdapForTeam(params: Github.EnterpriseUpdateLdapForTeamParams, callback?: Github.Callback): Promise; - syncLdapForTeam(params: Github.EnterpriseSyncLdapForTeamParams, callback?: Github.Callback): Promise; - getLicense(params: Github.EmptyParams, callback?: Github.Callback): Promise; - getPreReceiveEnvironment(params: Github.EnterpriseGetPreReceiveEnvironmentParams, callback?: Github.Callback): Promise; - getPreReceiveEnvironments(params: Github.EmptyParams, callback?: Github.Callback): Promise; - createPreReceiveEnvironment(params: Github.EnterpriseCreatePreReceiveEnvironmentParams, callback?: Github.Callback): Promise; - editPreReceiveEnvironment(params: Github.EnterpriseEditPreReceiveEnvironmentParams, callback?: Github.Callback): Promise; - deletePreReceiveEnvironment(params: Github.EnterpriseDeletePreReceiveEnvironmentParams, callback?: Github.Callback): Promise; - getPreReceiveEnvironmentDownloadStatus(params: Github.EnterpriseGetPreReceiveEnvironmentDownloadStatusParams, callback?: Github.Callback): Promise; - triggerPreReceiveEnvironmentDownload(params: Github.EnterpriseTriggerPreReceiveEnvironmentDownloadParams, callback?: Github.Callback): Promise; - getPreReceiveHook(params: Github.EnterpriseGetPreReceiveHookParams, callback?: Github.Callback): Promise; - getPreReceiveHooks(params: Github.EmptyParams, callback?: Github.Callback): Promise; - createPreReceiveHook(params: Github.EnterpriseCreatePreReceiveHookParams, callback?: Github.Callback): Promise; - editPreReceiveHook(params: Github.EnterpriseEditPreReceiveHookParams, callback?: Github.Callback): Promise; - deletePreReceiveHook(params: Github.EnterpriseDeletePreReceiveHookParams, callback?: Github.Callback): Promise; - queueIndexingJob(params: Github.EnterpriseQueueIndexingJobParams, callback?: Github.Callback): Promise; - createOrg(params: Github.EnterpriseCreateOrgParams, callback?: Github.Callback): Promise; - }; -} - -declare module "octokit-rest-es3" { - export = Github; -} \ No newline at end of file From 204bb8954a61c7355c0ffc6551313661ff77defa Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 09:21:36 -0500 Subject: [PATCH 0196/1008] Changing package and providing polyfill --- octorun/package-lock.json | 628 ++------------------------------------ octorun/package.json | 46 +-- 2 files changed, 29 insertions(+), 645 deletions(-) diff --git a/octorun/package-lock.json b/octorun/package-lock.json index 0a2cf1867..5a8839da0 100644 --- a/octorun/package-lock.json +++ b/octorun/package-lock.json @@ -1,609 +1,23 @@ { - "name": "octorun", - "version": "0.1.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/chai": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.2.tgz", - "integrity": "sha512-D8uQwKYUw2KESkorZ27ykzXgvkDJYXVEihGklgfp5I4HUP8D6IxtcdLTMB1emjQiWzV7WZ5ihm1cxIzVwjoleQ==", - "dev": true - }, - "@types/commander": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/@types/commander/-/commander-2.12.2.tgz", - "integrity": "sha512-0QEFiR8ljcHp9bAbWxecjVRuAMr16ivPiGOw6KFQBVrVd0RQIcM3xKdRisH2EDWgVWujiYtHwhSkSUoAAGzH7Q==", - "dev": true, - "requires": { - "commander": "2.14.1" - } - }, - "@types/mocha": { - "version": "2.2.48", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.48.tgz", - "integrity": "sha512-nlK/iyETgafGli8Zh9zJVCTicvU3iajSkRwOh3Hhiva598CMqNJ4NcVCGMTGKpGpTYj/9R8RLzS9NAykSSCqGw==", - "dev": true - }, - "@types/node": { - "version": "7.0.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.55.tgz", - "integrity": "sha512-diCxfWNT4g2UM9Y+BPgy4s3egcZ2qOXc0mXLauvbsBUq9SBKQfh0SmuEUEhJVFZt/p6UDsjg1s2EgfM6OSlp4g==", - "dev": true - }, - "@types/sinon": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-2.3.7.tgz", - "integrity": "sha512-w+LjztaZbgZWgt/y/VMP5BUAWLtSyoIJhXyW279hehLPyubDoBNwvhcj3WaSptcekuKYeTCVxrq60rdLc6ImJA==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "browser-stdout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", - "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", - "dev": true - }, - "chai": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz", - "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=", - "dev": true, - "requires": { - "assertion-error": "1.1.0", - "check-error": "1.0.2", - "deep-eql": "3.0.1", - "get-func-name": "2.0.0", - "pathval": "1.1.0", - "type-detect": "4.0.8" - } - }, - "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", - "dev": true, - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "5.2.0" - }, - "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", - "dev": true, - "requires": { - "has-flag": "3.0.0" - } - } - } - }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", - "dev": true - }, - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commander": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", - "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "diff": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", - "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "formatio": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz", - "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=", - "dev": true, - "requires": { - "samsam": "1.3.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", - "dev": true - }, - "glob": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", - "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true - }, - "growl": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", - "dev": true - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", - "dev": true - }, - "homedir-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", - "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", - "dev": true, - "requires": { - "parse-passwd": "1.0.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "json3": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", - "dev": true - }, - "lodash._baseassign": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", - "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", - "dev": true, - "requires": { - "lodash._basecopy": "3.0.1", - "lodash.keys": "3.1.2" - } - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "lodash._basecreate": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", - "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "lodash.create": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", - "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", - "dev": true, - "requires": { - "lodash._baseassign": "3.2.0", - "lodash._basecreate": "3.0.3", - "lodash._isiterateecall": "3.0.9" - } - }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "requires": { - "lodash._getnative": "3.9.1", - "lodash.isarguments": "3.1.0", - "lodash.isarray": "3.0.4" - } - }, - "lolex": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", - "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", - "dev": true - }, - "make-error": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", - "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "1.1.11" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "mocha": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", - "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==", - "dev": true, - "requires": { - "browser-stdout": "1.3.0", - "commander": "2.9.0", - "debug": "2.6.8", - "diff": "3.2.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.1", - "growl": "1.9.2", - "he": "1.1.1", - "json3": "3.3.2", - "lodash.create": "3.1.1", - "mkdirp": "0.5.1", - "supports-color": "3.1.2" - }, - "dependencies": { - "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true, - "requires": { - "graceful-readlink": "1.0.1" - } - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "native-promise-only": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", - "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "dev": true, - "requires": { - "isarray": "0.0.1" - } - }, - "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", - "dev": true - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, - "requires": { - "glob": "7.1.1" - } - }, - "samsam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", - "dev": true - }, - "sinon": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.4.1.tgz", - "integrity": "sha512-vFTrO9Wt0ECffDYIPSP/E5bBugt0UjcBQOfQUMh66xzkyPEnhl/vM2LRZi2ajuTdkH07sA6DzrM6KvdvGIH8xw==", - "dev": true, - "requires": { - "diff": "3.2.0", - "formatio": "1.2.0", - "lolex": "1.6.0", - "native-promise-only": "0.8.1", - "path-to-regexp": "1.7.0", - "samsam": "1.3.0", - "text-encoding": "0.6.4", - "type-detect": "4.0.8" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "0.5.7" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "supports-color": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", - "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", - "dev": true, - "requires": { - "has-flag": "1.0.0" - } - }, - "text-encoding": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", - "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", - "dev": true - }, - "ts-node": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-3.3.0.tgz", - "integrity": "sha1-wTxqMCTjC+EYDdUwOPwgkonUv2k=", - "dev": true, - "requires": { - "arrify": "1.0.1", - "chalk": "2.3.1", - "diff": "3.2.0", - "make-error": "1.3.4", - "minimist": "1.2.0", - "mkdirp": "0.5.1", - "source-map-support": "0.4.18", - "tsconfig": "6.0.0", - "v8flags": "3.0.2", - "yn": "2.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "tsconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-6.0.0.tgz", - "integrity": "sha1-aw6DdgA9evGGT434+J3QBZ/80DI=", - "dev": true, - "requires": { - "strip-bom": "3.0.0", - "strip-json-comments": "2.0.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "typescript": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz", - "integrity": "sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw==", - "dev": true - }, - "v8flags": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.2.tgz", - "integrity": "sha512-6sgSKoFw1UpUPd3cFdF7QGnrH6tDeBgW1F3v9gy8gLY0mlbiBXq8soy8aQpY6xeeCjH5K+JvC62Acp7gtl7wWA==", - "dev": true, - "requires": { - "homedir-polyfill": "1.0.1" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "yn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", - "dev": true - } - } + "name": "octorun", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "dotenv": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-1.2.0.tgz", + "integrity": "sha1-fNc+FuB/BXyAchR6W8OoZ38KtcY=" + }, + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==" + }, + "octokit-rest-nothing-to-see-here-kthxbye": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/octokit-rest-nothing-to-see-here-kthxbye/-/octokit-rest-nothing-to-see-here-kthxbye-1.0.0.tgz", + "integrity": "sha1-tdcZKisFpFWv6uu66os/eQpmDK8=" + } + } } diff --git a/octorun/package.json b/octorun/package.json index 19abf98d1..7e83036dd 100644 --- a/octorun/package.json +++ b/octorun/package.json @@ -1,46 +1,16 @@ { "name": "octorun", - "version": "0.1.0", + "version": "1.0.0", "description": "", - "repository": "", - "license": "MIT", + "main": "index.js", "scripts": { - "clean": "rimraf dist", - "build": "npm run clean && tsc --pretty", - "test": "npm run build && mocha --compilers ts:ts-node/register --recursive test/**/*-spec.ts", - "watch": "npm run build -- --watch", - "watch:test": "npm run test -- --watch" - }, - "author": { - "name": "Stanley Goldman", - "email": "Stanley.Goldman@gmail.com" - }, - "main": "dist/bin/app.js", - "typings": "dist/bin/app.d.ts", - "bin": { - "octorun": "bin/octorun" - }, - "files": [ - "bin", - "dist" - ], - "devDependencies": { - "@types/chai": "^4.0.0", - "@types/commander": "^2.3.31", - "@types/dotenv": "^4.0.2", - "@types/mocha": "^2.2.39", - "@types/node": "^7.0.5", - "@types/sinon": "^2.3.0", - "chai": "^4.0.1", - "mocha": "^3.2.0", - "rimraf": "^2.6.1", - "sinon": "^2.3.2", - "ts-node": "^3.0.4", - "typescript": "^2.2.1" + "test": "echo \"Error: no test specified\" && exit 1" }, + "author": "", + "license": "ISC", "dependencies": { - "commander": "^2.9.0", - "dotenv": "^5.0.1", - "octokit-rest-es3": "github:gr2m/octokit-rest-es3" + "dotenv": "^1.0.0", + "es6-promise": "^4.2.4", + "octokit-rest-nothing-to-see-here-kthxbye": "^1.0.0" } } From 5b80d1638cab9bd31ac1cb4c776b1cae19e45023 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 09:21:59 -0500 Subject: [PATCH 0197/1008] Adding a modern version of octorun --- octorun-modern/.env.template | 2 + octorun-modern/.gitignore | 3 ++ octorun-modern/index.js | 26 +++++++++++++ octorun-modern/package-lock.json | 64 ++++++++++++++++++++++++++++++++ octorun-modern/package.json | 15 ++++++++ octorun/index.js | 34 +++++++++++++++++ 6 files changed, 144 insertions(+) create mode 100644 octorun-modern/.env.template create mode 100644 octorun-modern/.gitignore create mode 100644 octorun-modern/index.js create mode 100644 octorun-modern/package-lock.json create mode 100644 octorun-modern/package.json create mode 100644 octorun/index.js diff --git a/octorun-modern/.env.template b/octorun-modern/.env.template new file mode 100644 index 000000000..7eaafeb53 --- /dev/null +++ b/octorun-modern/.env.template @@ -0,0 +1,2 @@ +OCTOKIT_CLIENT_ID= +OCTOKIT_CLIENT_SECRET= \ No newline at end of file diff --git a/octorun-modern/.gitignore b/octorun-modern/.gitignore new file mode 100644 index 000000000..ef4fcce9d --- /dev/null +++ b/octorun-modern/.gitignore @@ -0,0 +1,3 @@ +.env +node_modules +npm-debug.log diff --git a/octorun-modern/index.js b/octorun-modern/index.js new file mode 100644 index 000000000..b36e9b156 --- /dev/null +++ b/octorun-modern/index.js @@ -0,0 +1,26 @@ +require("dotenv").config(); + +console.log("NodeJS Path: ", process.argv[0]); + +console.log(process.env.OCTOKIT_CLIENT_ID); +console.log(process.env.OCTOKIT_CLIENT_SECRET); + +var GitHub = require('@octokit/rest'); +var gitHub = new GitHub(); + +var authParams = { + client_id: process.env.OCTOKIT_CLIENT_ID, + client_secret: process.env.OCTOKIT_CLIENT_SECRET, + scopes: ["user", "repo", "gist", "write:public_key"] +}; + +gitHub.authorization.getOrCreateAuthorizationForApp(authParams, function (error, result) { + if (error) { + console.log("error", error, error.stack); + } + else { + console.log("result", result); + } + + process.exit(); +}); \ No newline at end of file diff --git a/octorun-modern/package-lock.json b/octorun-modern/package-lock.json new file mode 100644 index 000000000..35d7fa8f8 --- /dev/null +++ b/octorun-modern/package-lock.json @@ -0,0 +1,64 @@ +{ + "name": "octorun-modern", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@octokit/rest": { + "version": "14.0.9", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-14.0.9.tgz", + "integrity": "sha512-irP9phKfTXEZIcW2R+VNCtGHZJrXMWmSYp6RRfFn4BtAqtDRXF5z9JxCEQlAhNBf6X1koNi5k49tIAAAEJNlVQ==", + "requires": { + "before-after-hook": "1.1.0", + "debug": "3.1.0", + "is-array-buffer": "1.0.0", + "is-stream": "1.1.0", + "lodash": "4.17.5", + "url-template": "2.0.8" + } + }, + "before-after-hook": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-1.1.0.tgz", + "integrity": "sha512-VOMDtYPwLbIncTxNoSzRyvaMxtXmLWLUqr8k5AfC1BzLk34HvBXaQX8snOwQZ4c0aX8aSERqtJSiI9/m2u5kuA==" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "dotenv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-1.0.0.tgz", + "integrity": "sha1-/cUn/GZBHGHXSjq50Znr+HRTLNQ=" + }, + "is-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-1.0.0.tgz", + "integrity": "sha512-KtzJzWuC1kZQ377GJbEsoBh0LuQh1uaZnQg8oL2LcDkY/Ny8rpAzu21Ls3oph3SEKXbnrLHt3rAUVm28iuEPfw==" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + } + } +} diff --git a/octorun-modern/package.json b/octorun-modern/package.json new file mode 100644 index 000000000..9059e6e92 --- /dev/null +++ b/octorun-modern/package.json @@ -0,0 +1,15 @@ +{ + "name": "octorun-modern", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@octokit/rest": "^14.0.9", + "dotenv": "^1.0.0" + } +} diff --git a/octorun/index.js b/octorun/index.js new file mode 100644 index 000000000..e66262ede --- /dev/null +++ b/octorun/index.js @@ -0,0 +1,34 @@ +// polyfill Buffer.from +if (!Buffer.from) { + Buffer.from = function (data, encoding, length) { + return new Buffer(data, encoding, length) + } +} + +require("dotenv").config(); +require('es6-promise').polyfill(); + +console.log("NodeJS Path: ", process.argv[0]); + +console.log(process.env.OCTOKIT_CLIENT_ID); +console.log(process.env.OCTOKIT_CLIENT_SECRET); + +var GitHub = require('octokit-rest-nothing-to-see-here-kthxbye'); +var gitHub = new GitHub(); + +var authParams = { + client_id: process.env.OCTOKIT_CLIENT_ID, + client_secret: process.env.OCTOKIT_CLIENT_SECRET, + scopes: ["user", "repo", "gist", "write:public_key"] +}; + +gitHub.authorization.getOrCreateAuthorizationForApp(authParams, function (error, result) { + if (error) { + console.log("error", error, error.stack); + } + else { + console.log("result", result); + } + + process.exit(); +}); \ No newline at end of file From caf09610db5071631f06602c486a37d79909849c Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 10:49:17 -0500 Subject: [PATCH 0198/1008] I understand how i'm supposed to do this now --- octorun-modern/.env.template | 3 +- octorun-modern/index.js | 80 ++++++++++++++++++++++++-------- octorun-modern/package-lock.json | 5 ++ octorun-modern/package.json | 3 +- 4 files changed, 70 insertions(+), 21 deletions(-) diff --git a/octorun-modern/.env.template b/octorun-modern/.env.template index 7eaafeb53..53bc61631 100644 --- a/octorun-modern/.env.template +++ b/octorun-modern/.env.template @@ -1,2 +1,3 @@ OCTOKIT_CLIENT_ID= -OCTOKIT_CLIENT_SECRET= \ No newline at end of file +OCTOKIT_CLIENT_SECRET= +OCTOKIT_APP_NAME = \ No newline at end of file diff --git a/octorun-modern/index.js b/octorun-modern/index.js index b36e9b156..246fc0c82 100644 --- a/octorun-modern/index.js +++ b/octorun-modern/index.js @@ -1,26 +1,68 @@ -require("dotenv").config(); +const readlineSync = require("readline-sync"); +const octokit = require('@octokit/rest')({ + timeout: 0, // 0 means no request timeout + requestMedia: 'application/vnd.github.v3+json', + headers: { + 'user-agent': 'octokit/rest.js v1.2.3' // v1.2.3 will be current version + }, + + // change for custom GitHub Enterprise URL + //host: 'api.github.com', + //pathPrefix: '', + //protocol: 'https', + //port: 443, + + // Node only: advanced request options can be passed as http(s) agent + //agent: undefined + }); console.log("NodeJS Path: ", process.argv[0]); -console.log(process.env.OCTOKIT_CLIENT_ID); -console.log(process.env.OCTOKIT_CLIENT_SECRET); +require("dotenv").config(); + +const clientId = process.env.OCTOKIT_CLIENT_ID; +const clientSecret = process.env.OCTOKIT_CLIENT_SECRET; + +const appName = process.env.OCTORUN_APP_NAME | "octorun"; +let user = process.env.OCTORUN_USER; +const token = process.env.OCTORUN_TOKEN; + +const scopes = ["user", "repo", "gist", "write:public_key"]; + +if(user != null && token != null) +{ + +} +else +{ + user = readlineSync.question('User: '); + + var pwd = readlineSync.question('Password: ', { + hideEchoBack: true + }); + + octokit.authenticate({ + type:"basic", + username:user, + password:pwd + }); -var GitHub = require('@octokit/rest'); -var gitHub = new GitHub(); + octokit.authorization.create({ + scopes: scopes, + note: appName, + client_id: clientId, + client_secret: clientSecret + }, function(err, res) { -var authParams = { - client_id: process.env.OCTOKIT_CLIENT_ID, - client_secret: process.env.OCTOKIT_CLIENT_SECRET, - scopes: ["user", "repo", "gist", "write:public_key"] -}; + console.log("err", err, "res", res); -gitHub.authorization.getOrCreateAuthorizationForApp(authParams, function (error, result) { - if (error) { - console.log("error", error, error.stack); - } - else { - console.log("result", result); - } + if(err) + { + + } + else + { - process.exit(); -}); \ No newline at end of file + } + }); +} diff --git a/octorun-modern/package-lock.json b/octorun-modern/package-lock.json index 35d7fa8f8..a769d5561 100644 --- a/octorun-modern/package-lock.json +++ b/octorun-modern/package-lock.json @@ -55,6 +55,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "readline-sync": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.9.tgz", + "integrity": "sha1-PtqOZfI80qF+YTAbHwADOWr17No=" + }, "url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", diff --git a/octorun-modern/package.json b/octorun-modern/package.json index 9059e6e92..7a3648841 100644 --- a/octorun-modern/package.json +++ b/octorun-modern/package.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "@octokit/rest": "^14.0.9", - "dotenv": "^1.0.0" + "dotenv": "^1.0.0", + "readline-sync": "^1.4.9" } } From e52090a6a615bda3cf4f88b1f38274f180c2b063 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 13:33:42 -0500 Subject: [PATCH 0199/1008] I can two factor auth --- octorun/index.js | 122 ++++++++++++++++++++++++++++++++------ octorun/package-lock.json | 23 ------- octorun/package.json | 3 +- 3 files changed, 106 insertions(+), 42 deletions(-) delete mode 100644 octorun/package-lock.json diff --git a/octorun/index.js b/octorun/index.js index e66262ede..4b4ff183c 100644 --- a/octorun/index.js +++ b/octorun/index.js @@ -1,34 +1,120 @@ // polyfill Buffer.from if (!Buffer.from) { Buffer.from = function (data, encoding, length) { - return new Buffer(data, encoding, length) + return new Buffer(data, encoding, length) } } require("dotenv").config(); require('es6-promise').polyfill(); +var readlineSync = require("readline-sync"); +var http = require("http"); console.log("NodeJS Path: ", process.argv[0]); -console.log(process.env.OCTOKIT_CLIENT_ID); -console.log(process.env.OCTOKIT_CLIENT_SECRET); +var clientId = process.env.OCTOKIT_CLIENT_ID; +var clientSecret = process.env.OCTOKIT_CLIENT_SECRET; +var appName = process.env.OCTORUN_APP_NAME | "octorun"; +var user = process.env.OCTORUN_USER; +var token = process.env.OCTORUN_TOKEN; -var GitHub = require('octokit-rest-nothing-to-see-here-kthxbye'); -var gitHub = new GitHub(); +var scopes = ["user", "repo", "gist", "write:public_key"]; -var authParams = { - client_id: process.env.OCTOKIT_CLIENT_ID, - client_secret: process.env.OCTOKIT_CLIENT_SECRET, - scopes: ["user", "repo", "gist", "write:public_key"] +var Octokit = require('octokit-rest-nothing-to-see-here-kthxbye'); +var createOctokit = function () { + return Octokit({ + timeout: 0, + requestMedia: 'application/vnd.github.v3+json', + headers: { + 'user-agent': 'octokit/rest.js v1.2.3' + } + + // change for custom GitHub Enterprise URL + //host: 'api.github.com', + //pathPrefix: '', + //protocol: 'https', + //port: 443 + }); }; -gitHub.authorization.getOrCreateAuthorizationForApp(authParams, function (error, result) { - if (error) { - console.log("error", error, error.stack); - } - else { - console.log("result", result); - } +var handleBasicAuthentication = function (onSuccess, onRequiresTwoFa, onFailure) { + var user = readlineSync.question('User: '); + + var pwd = readlineSync.question('Password: ', { + hideEchoBack: true + }); + + var octokit = createOctokit(); + + octokit.authenticate({ + type: "basic", + username: user, + password: pwd + }); + + octokit.authorization.create({ + scopes: scopes, + note: appName, + client_id: clientId, + client_secret: clientSecret + }, function (err, res) { + if (err) { + if (err.message === '{"message":"Must specify two-factor authentication OTP code.","documentation_url":"https://developer.github.com/v3/auth#working-with-two-factor-authentication"}') { + onRequiresTwoFa(); + return; + } + else { + onFailure(err) + } + } + else { + onSuccess(res.data.token); + } + }); +} + +var handleTwoFactorAuthentication = function (onSuccess, onFailure) { + var user = readlineSync.question('User: '); - process.exit(); -}); \ No newline at end of file + var pwd = readlineSync.question('Password: ', { + hideEchoBack: true + }); + + var twofa = readlineSync.question('TwoFactor: '); + + var octokit = createOctokit(); + + octokit.authenticate({ + type: "basic", + username: user, + password: pwd + }); + + octokit.authorization.create({ + scopes: scopes, + note: appName, + client_id: clientId, + client_secret: clientSecret, + headers: { + "X-GitHub-OTP": twofa + } + }, function (err, res) { + if (err) { + onFailure(err) + } + else { + onSuccess(res.data.token); + } + }); +} + +if (user != null && token != null) { + +} +else { + handleTwoFactorAuthentication(function (token) { + console.log("token", token); + }, function (err) { + console.log("error", error); + }) +} diff --git a/octorun/package-lock.json b/octorun/package-lock.json deleted file mode 100644 index 5a8839da0..000000000 --- a/octorun/package-lock.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "octorun", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "dotenv": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-1.2.0.tgz", - "integrity": "sha1-fNc+FuB/BXyAchR6W8OoZ38KtcY=" - }, - "es6-promise": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", - "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==" - }, - "octokit-rest-nothing-to-see-here-kthxbye": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/octokit-rest-nothing-to-see-here-kthxbye/-/octokit-rest-nothing-to-see-here-kthxbye-1.0.0.tgz", - "integrity": "sha1-tdcZKisFpFWv6uu66os/eQpmDK8=" - } - } -} diff --git a/octorun/package.json b/octorun/package.json index 7e83036dd..42b714409 100644 --- a/octorun/package.json +++ b/octorun/package.json @@ -11,6 +11,7 @@ "dependencies": { "dotenv": "^1.0.0", "es6-promise": "^4.2.4", - "octokit-rest-nothing-to-see-here-kthxbye": "^1.0.0" + "octokit-rest-nothing-to-see-here-kthxbye": "^1.0.1", + "readline-sync": "^1.4.9" } } From 4d28a19b59a74ad9e8d74385e5be6cd9e9a4fce0 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 14:06:17 -0500 Subject: [PATCH 0200/1008] Completed functionality to authenticate --- octorun/bin/octorun | 5 ++ octorun/bin/octorun-login | 3 + octorun/package.json | 2 + octorun/{index.js => src/authentication.js} | 67 +++++---------------- octorun/src/bin/app-login.js | 30 +++++++++ octorun/src/bin/app.js | 8 +++ octorun/src/configuration.js | 15 +++++ octorun/src/octokit.js | 20 ++++++ 8 files changed, 97 insertions(+), 53 deletions(-) create mode 100644 octorun/bin/octorun create mode 100644 octorun/bin/octorun-login rename octorun/{index.js => src/authentication.js} (52%) create mode 100644 octorun/src/bin/app-login.js create mode 100644 octorun/src/bin/app.js create mode 100644 octorun/src/configuration.js create mode 100644 octorun/src/octokit.js diff --git a/octorun/bin/octorun b/octorun/bin/octorun new file mode 100644 index 000000000..c3e1f57c8 --- /dev/null +++ b/octorun/bin/octorun @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +console.log("NodeJs", process.argv[0]); + +require('../src/bin/app.js'); diff --git a/octorun/bin/octorun-login b/octorun/bin/octorun-login new file mode 100644 index 000000000..f74f2b860 --- /dev/null +++ b/octorun/bin/octorun-login @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('../src/bin/app-login.js'); diff --git a/octorun/package.json b/octorun/package.json index 42b714409..2ab332898 100644 --- a/octorun/package.json +++ b/octorun/package.json @@ -6,9 +6,11 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, + "main": "src/app.js", "author": "", "license": "ISC", "dependencies": { + "commander": "^2.14.1", "dotenv": "^1.0.0", "es6-promise": "^4.2.4", "octokit-rest-nothing-to-see-here-kthxbye": "^1.0.1", diff --git a/octorun/index.js b/octorun/src/authentication.js similarity index 52% rename from octorun/index.js rename to octorun/src/authentication.js index 4b4ff183c..ebaebd26e 100644 --- a/octorun/index.js +++ b/octorun/src/authentication.js @@ -1,42 +1,9 @@ -// polyfill Buffer.from -if (!Buffer.from) { - Buffer.from = function (data, encoding, length) { - return new Buffer(data, encoding, length) - } -} - -require("dotenv").config(); -require('es6-promise').polyfill(); var readlineSync = require("readline-sync"); -var http = require("http"); - -console.log("NodeJS Path: ", process.argv[0]); - -var clientId = process.env.OCTOKIT_CLIENT_ID; -var clientSecret = process.env.OCTOKIT_CLIENT_SECRET; -var appName = process.env.OCTORUN_APP_NAME | "octorun"; -var user = process.env.OCTORUN_USER; -var token = process.env.OCTORUN_TOKEN; +var config = require("./configuration"); +var octokitWrapper = require("./octokit"); var scopes = ["user", "repo", "gist", "write:public_key"]; -var Octokit = require('octokit-rest-nothing-to-see-here-kthxbye'); -var createOctokit = function () { - return Octokit({ - timeout: 0, - requestMedia: 'application/vnd.github.v3+json', - headers: { - 'user-agent': 'octokit/rest.js v1.2.3' - } - - // change for custom GitHub Enterprise URL - //host: 'api.github.com', - //pathPrefix: '', - //protocol: 'https', - //port: 443 - }); -}; - var handleBasicAuthentication = function (onSuccess, onRequiresTwoFa, onFailure) { var user = readlineSync.question('User: '); @@ -44,7 +11,7 @@ var handleBasicAuthentication = function (onSuccess, onRequiresTwoFa, onFailure) hideEchoBack: true }); - var octokit = createOctokit(); + var octokit = octokitWrapper.createOctokit(); octokit.authenticate({ type: "basic", @@ -54,9 +21,9 @@ var handleBasicAuthentication = function (onSuccess, onRequiresTwoFa, onFailure) octokit.authorization.create({ scopes: scopes, - note: appName, - client_id: clientId, - client_secret: clientSecret + note: config.appName, + client_id: config.clientId, + client_secret: config.clientSecret }, function (err, res) { if (err) { if (err.message === '{"message":"Must specify two-factor authentication OTP code.","documentation_url":"https://developer.github.com/v3/auth#working-with-two-factor-authentication"}') { @@ -82,7 +49,7 @@ var handleTwoFactorAuthentication = function (onSuccess, onFailure) { var twofa = readlineSync.question('TwoFactor: '); - var octokit = createOctokit(); + var octokit = octokitWrapper.createOctokit(); octokit.authenticate({ type: "basic", @@ -92,9 +59,9 @@ var handleTwoFactorAuthentication = function (onSuccess, onFailure) { octokit.authorization.create({ scopes: scopes, - note: appName, - client_id: clientId, - client_secret: clientSecret, + note: config.appName, + client_id: config.clientId, + client_secret: config.clientSecret, headers: { "X-GitHub-OTP": twofa } @@ -108,13 +75,7 @@ var handleTwoFactorAuthentication = function (onSuccess, onFailure) { }); } -if (user != null && token != null) { - -} -else { - handleTwoFactorAuthentication(function (token) { - console.log("token", token); - }, function (err) { - console.log("error", error); - }) -} +module.exports = { + handleBasicAuthentication: handleBasicAuthentication, + handleTwoFactorAuthentication: handleTwoFactorAuthentication, +}; \ No newline at end of file diff --git a/octorun/src/bin/app-login.js b/octorun/src/bin/app-login.js new file mode 100644 index 000000000..69be74001 --- /dev/null +++ b/octorun/src/bin/app-login.js @@ -0,0 +1,30 @@ +var commander = require("commander"); +var package = require('../../package.json') +var authentication = require('../authentication') + +commander + .version(package.version) + .option('-t, --twoFactor') + .parse(process.argv); + +if (commander.twoFactor) { + authentication.handleTwoFactorAuthentication(function (token) { + console.log(token); + process.exit(); + }, function () { + console.log("Must specify two-factor authentication OTP code."); + process.exit(); + }, function (err) { + console.log(err); + process.exit(-1); + }); +} +else { + authentication.handleBasicAuthentication(function (token) { + console.log(token); + process.exit(); + }, function (err) { + console.log(err); + process.exit(-1); + }); +} \ No newline at end of file diff --git a/octorun/src/bin/app.js b/octorun/src/bin/app.js new file mode 100644 index 000000000..27e3dcd44 --- /dev/null +++ b/octorun/src/bin/app.js @@ -0,0 +1,8 @@ + +var commander = require("commander"); +var package = require('../../package.json') + +commander + .version(package.version) + .command('login [-t]', 'Authenticate') + .parse(process.argv); \ No newline at end of file diff --git a/octorun/src/configuration.js b/octorun/src/configuration.js new file mode 100644 index 000000000..5ae9d40e8 --- /dev/null +++ b/octorun/src/configuration.js @@ -0,0 +1,15 @@ +require("dotenv").config(); + +var clientId = process.env.OCTOKIT_CLIENT_ID; +var clientSecret = process.env.OCTOKIT_CLIENT_SECRET; +var appName = process.env.OCTORUN_APP_NAME | "octorun"; +var user = process.env.OCTORUN_USER; +var token = process.env.OCTORUN_TOKEN; + +module.exports = { + clientId: clientId, + clientSecret: clientSecret, + appName: appName, + user: user, + token: token, +}; \ No newline at end of file diff --git a/octorun/src/octokit.js b/octorun/src/octokit.js new file mode 100644 index 000000000..a13bea657 --- /dev/null +++ b/octorun/src/octokit.js @@ -0,0 +1,20 @@ +require('es6-promise').polyfill(); +var Octokit = require('octokit-rest-nothing-to-see-here-kthxbye'); + +var createOctokit = function () { + return Octokit({ + timeout: 0, + requestMedia: 'application/vnd.github.v3+json', + headers: { + 'user-agent': 'octokit/rest.js v1.2.3' + } + + // change for custom GitHub Enterprise URL + //host: 'api.github.com', + //pathPrefix: '', + //protocol: 'https', + //port: 443 + }); +}; + +module.exports = { createOctokit: createOctokit }; \ No newline at end of file From 0bfff0940cfaad850971c73a32cb7c241bc7bfd1 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 14:47:06 -0500 Subject: [PATCH 0201/1008] Functionality to validate the user and get an organization list --- octorun/.env.template | 4 +++- octorun/bin/octorun | 2 +- octorun/bin/octorun-organizations | 3 +++ octorun/bin/octorun-validate | 3 +++ octorun/src/api.js | 31 ++++++++++++++++++++++++++++ octorun/src/bin/app-login.js | 6 +++--- octorun/src/bin/app-organizations.js | 19 +++++++++++++++++ octorun/src/bin/app-validate.js | 20 ++++++++++++++++++ octorun/src/bin/app.js | 2 ++ octorun/src/configuration.js | 2 +- 10 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 octorun/bin/octorun-organizations create mode 100644 octorun/bin/octorun-validate create mode 100644 octorun/src/api.js create mode 100644 octorun/src/bin/app-organizations.js create mode 100644 octorun/src/bin/app-validate.js diff --git a/octorun/.env.template b/octorun/.env.template index 7eaafeb53..2c1f93479 100644 --- a/octorun/.env.template +++ b/octorun/.env.template @@ -1,2 +1,4 @@ OCTOKIT_CLIENT_ID= -OCTOKIT_CLIENT_SECRET= \ No newline at end of file +OCTOKIT_CLIENT_SECRET= +OCTORUN_USER= +OCTORUN_TOKEN= \ No newline at end of file diff --git a/octorun/bin/octorun b/octorun/bin/octorun index c3e1f57c8..f7c15dc90 100644 --- a/octorun/bin/octorun +++ b/octorun/bin/octorun @@ -1,5 +1,5 @@ #!/usr/bin/env node -console.log("NodeJs", process.argv[0]); +console.log("node:", process.argv[0]); require('../src/bin/app.js'); diff --git a/octorun/bin/octorun-organizations b/octorun/bin/octorun-organizations new file mode 100644 index 000000000..bf6c9f558 --- /dev/null +++ b/octorun/bin/octorun-organizations @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('../src/bin/app-organizations.js'); diff --git a/octorun/bin/octorun-validate b/octorun/bin/octorun-validate new file mode 100644 index 000000000..e81615852 --- /dev/null +++ b/octorun/bin/octorun-validate @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('../src/bin/app-validate.js'); diff --git a/octorun/src/api.js b/octorun/src/api.js new file mode 100644 index 000000000..3f87d1dd0 --- /dev/null +++ b/octorun/src/api.js @@ -0,0 +1,31 @@ +var readlineSync = require("readline-sync"); +var config = require("./configuration"); +var octokitWrapper = require("./octokit"); + +function ApiWrapper() { + this.octokit = octokitWrapper.createOctokit(); + + if (!config.user || !config.token) { + throw "User and/or Token missing"; + } + + this.octokit.authenticate({ + type: "oauth", + token: config.token + }); +} + +ApiWrapper.prototype.verifyUser = function (callback) { + this.octokit.users.get({}, function(error, result){ + callback(error, (!result) ? null : result.data.login); + }); +}; + +ApiWrapper.prototype.getOrgs = function (callback) { + var position = { page: 0, per_page: 100 }; + this.octokit.users.getOrgs(position, function (error, result) { + callback(error, (!result) ? null : result.data.map(function (item) { return item.login; })); + }); +}; + +module.exports = ApiWrapper; \ No newline at end of file diff --git a/octorun/src/bin/app-login.js b/octorun/src/bin/app-login.js index 69be74001..c0b7bddb2 100644 --- a/octorun/src/bin/app-login.js +++ b/octorun/src/bin/app-login.js @@ -11,9 +11,6 @@ if (commander.twoFactor) { authentication.handleTwoFactorAuthentication(function (token) { console.log(token); process.exit(); - }, function () { - console.log("Must specify two-factor authentication OTP code."); - process.exit(); }, function (err) { console.log(err); process.exit(-1); @@ -23,6 +20,9 @@ else { authentication.handleBasicAuthentication(function (token) { console.log(token); process.exit(); + }, function () { + console.log("Must specify two-factor authentication OTP code."); + process.exit(1); }, function (err) { console.log(err); process.exit(-1); diff --git a/octorun/src/bin/app-organizations.js b/octorun/src/bin/app-organizations.js new file mode 100644 index 000000000..e57acc8d3 --- /dev/null +++ b/octorun/src/bin/app-organizations.js @@ -0,0 +1,19 @@ +var commander = require("commander"); +var package = require('../../package.json') +var ApiWrapper = require('../api') + +commander + .version(package.version) + .parse(process.argv); + +var apiWrapper = new ApiWrapper(); +apiWrapper.getOrgs(function (error, result) { + if (error) { + console.log(error); + process.exit(-1); + } + else { + console.log(result); + process.exit(); + } +}); \ No newline at end of file diff --git a/octorun/src/bin/app-validate.js b/octorun/src/bin/app-validate.js new file mode 100644 index 000000000..5e63750bd --- /dev/null +++ b/octorun/src/bin/app-validate.js @@ -0,0 +1,20 @@ +var commander = require("commander"); +var package = require('../../package.json') +var ApiWrapper = require('../api') + +commander + .version(package.version) + .parse(process.argv); + +var apiWrapper = new ApiWrapper(); + +apiWrapper.verifyUser(function (error, result) { + if (error) { + console.log(error); + process.exit(-1); + } + else { + console.log(result); + process.exit(); + } +}); \ No newline at end of file diff --git a/octorun/src/bin/app.js b/octorun/src/bin/app.js index 27e3dcd44..d144ea1ac 100644 --- a/octorun/src/bin/app.js +++ b/octorun/src/bin/app.js @@ -5,4 +5,6 @@ var package = require('../../package.json') commander .version(package.version) .command('login [-t]', 'Authenticate') + .command('validate', 'Validate Current User') + .command('organizations', 'Get Organizations') .parse(process.argv); \ No newline at end of file diff --git a/octorun/src/configuration.js b/octorun/src/configuration.js index 5ae9d40e8..4d9474b40 100644 --- a/octorun/src/configuration.js +++ b/octorun/src/configuration.js @@ -11,5 +11,5 @@ module.exports = { clientSecret: clientSecret, appName: appName, user: user, - token: token, + token: token }; \ No newline at end of file From 30dd778a09808d6831dd7333999dd7f6082561d9 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 15:01:25 -0500 Subject: [PATCH 0202/1008] An orgs function that will paginate all pages --- octorun/src/api.js | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/octorun/src/api.js b/octorun/src/api.js index 3f87d1dd0..3c413367a 100644 --- a/octorun/src/api.js +++ b/octorun/src/api.js @@ -16,16 +16,37 @@ function ApiWrapper() { } ApiWrapper.prototype.verifyUser = function (callback) { - this.octokit.users.get({}, function(error, result){ + this.octokit.users.get({}, function (error, result) { callback(error, (!result) ? null : result.data.login); }); }; ApiWrapper.prototype.getOrgs = function (callback) { - var position = { page: 0, per_page: 100 }; - this.octokit.users.getOrgs(position, function (error, result) { - callback(error, (!result) ? null : result.data.map(function (item) { return item.login; })); - }); + var perPageCount = 100; + var organizations = []; + var position = { page: 1, per_page: perPageCount }; + + var that = this; + var getOrgsAtPosition = function () { + that.octokit.users.getOrgs(position, function (error, result) { + for (var index = 0; index < result.data.length; index++) { + var element = result.data[index]; + organizations.push(element); + } + + if (result.data.length == perPageCount) { + position.page = position.page + 1; + getOrgsAtPosition(); + } + else { + callback(error, organizations.map(function (item) { + return item.login; + })); + } + }); + } + + getOrgsAtPosition(); }; module.exports = ApiWrapper; \ No newline at end of file From b80a0212b17e85bd386f9e0bf790ace808c2f958 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 15:28:57 -0500 Subject: [PATCH 0203/1008] Added functionality to publish a repo --- octorun/bin/octorun-publish | 3 +++ octorun/src/api.js | 22 ++++++++++++++++++++ octorun/src/bin/app-publish.js | 38 ++++++++++++++++++++++++++++++++++ octorun/src/bin/app.js | 3 ++- 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 octorun/bin/octorun-publish create mode 100644 octorun/src/bin/app-publish.js diff --git a/octorun/bin/octorun-publish b/octorun/bin/octorun-publish new file mode 100644 index 000000000..c95bdbb44 --- /dev/null +++ b/octorun/bin/octorun-publish @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('../src/bin/app-publish.js'); diff --git a/octorun/src/api.js b/octorun/src/api.js index 3c413367a..3cc79b581 100644 --- a/octorun/src/api.js +++ b/octorun/src/api.js @@ -49,4 +49,26 @@ ApiWrapper.prototype.getOrgs = function (callback) { getOrgsAtPosition(); }; +ApiWrapper.prototype.publish = function (name, desc, private, organization, callback) { + if (organization) { + this.octokit.repos.createForOrg({ + org: organization, + name: name, + description: desc, + private: private + }, function (error, result) { + callback(error, (!result) ? null : result.data.git_url); + }); + } + else { + this.octokit.repos.create({ + name: name, + description: desc, + private: private + }, function (error, result) { + callback(error, (!result) ? null : result.data.git_url); + }); + } +}; + module.exports = ApiWrapper; \ No newline at end of file diff --git a/octorun/src/bin/app-publish.js b/octorun/src/bin/app-publish.js new file mode 100644 index 000000000..a02033276 --- /dev/null +++ b/octorun/src/bin/app-publish.js @@ -0,0 +1,38 @@ +var commander = require("commander"); +var package = require('../../package.json') +var ApiWrapper = require('../api') + +commander + .version(package.version) + .option('-r, --repository ') + .option('-d, --description ') + .option('-o, --organization ') + .option('-p, --private') + .parse(process.argv); + +if(!commander.repository) +{ + console.log("repository required"); + commander.help(); + process.exit(-1); + return; +} + +var private = false; +if (commander.private) { + private = true; +} + +var apiWrapper = new ApiWrapper(); + +apiWrapper.publish(commander.repository, commander.description, private, commander.organization, + function (error, result) { + if (error) { + console.log(error); + process.exit(-1); + } + else { + console.log(result); + process.exit(); + } + }); \ No newline at end of file diff --git a/octorun/src/bin/app.js b/octorun/src/bin/app.js index d144ea1ac..c80c4a07c 100644 --- a/octorun/src/bin/app.js +++ b/octorun/src/bin/app.js @@ -4,7 +4,8 @@ var package = require('../../package.json') commander .version(package.version) - .command('login [-t]', 'Authenticate') + .command('login', 'Authenticate') .command('validate', 'Validate Current User') .command('organizations', 'Get Organizations') + .command('publish', 'Publish') .parse(process.argv); \ No newline at end of file From 831728b9225c0fcb91286b95a45c40b5752972fd Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 15:30:42 -0500 Subject: [PATCH 0204/1008] Removing unused package --- octorun/package.json | 1 - octorun/src/octokit.js | 1 - 2 files changed, 2 deletions(-) diff --git a/octorun/package.json b/octorun/package.json index 2ab332898..2fd6a68ce 100644 --- a/octorun/package.json +++ b/octorun/package.json @@ -12,7 +12,6 @@ "dependencies": { "commander": "^2.14.1", "dotenv": "^1.0.0", - "es6-promise": "^4.2.4", "octokit-rest-nothing-to-see-here-kthxbye": "^1.0.1", "readline-sync": "^1.4.9" } diff --git a/octorun/src/octokit.js b/octorun/src/octokit.js index a13bea657..f75250491 100644 --- a/octorun/src/octokit.js +++ b/octorun/src/octokit.js @@ -1,4 +1,3 @@ -require('es6-promise').polyfill(); var Octokit = require('octokit-rest-nothing-to-see-here-kthxbye'); var createOctokit = function () { From 044e3ff19f356f76a8acea6dd4c773e894a9ebe8 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 16:07:25 -0500 Subject: [PATCH 0205/1008] Functionality to submit Unity usage --- octorun/bin/octorun-usage | 3 +++ octorun/src/bin/app-usage.js | 42 ++++++++++++++++++++++++++++++++++++ octorun/src/bin/app.js | 1 + 3 files changed, 46 insertions(+) create mode 100644 octorun/bin/octorun-usage create mode 100644 octorun/src/bin/app-usage.js diff --git a/octorun/bin/octorun-usage b/octorun/bin/octorun-usage new file mode 100644 index 000000000..8366ae34e --- /dev/null +++ b/octorun/bin/octorun-usage @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('../src/bin/app-usage.js'); diff --git a/octorun/src/bin/app-usage.js b/octorun/src/bin/app-usage.js new file mode 100644 index 000000000..c3f6ea5f6 --- /dev/null +++ b/octorun/src/bin/app-usage.js @@ -0,0 +1,42 @@ +var commander = require("commander"); +var package = require('../../package.json') +var readlineSync = require("readline-sync"); +var endOfLine = require('os').EOL; + +commander + .version(package.version) + .parse(process.argv); + +var postData = readlineSync.question(); + +var https = require('https'); + +var options = { + hostname: 'central.github.com', + path: '/api/usage/unity', + method: 'POST', + headers: { + 'Content-Type': 'application/json' + } +}; + +var req = https.request(options, function (res) { + console.log('statusCode:', res.statusCode); + + res.on('data', function (d) { + process.stdout.write(d); + process.stdout.write(endOfLine); + }); + + res.on('end', function (d) { + process.exit(); + }); +}); + +req.on('error', function (e) { + console.error(e); + process.exit(-1); +}); + +req.write(postData); +req.end(); \ No newline at end of file diff --git a/octorun/src/bin/app.js b/octorun/src/bin/app.js index c80c4a07c..e40d738b2 100644 --- a/octorun/src/bin/app.js +++ b/octorun/src/bin/app.js @@ -8,4 +8,5 @@ commander .command('validate', 'Validate Current User') .command('organizations', 'Get Organizations') .command('publish', 'Publish') + .command('usage', 'Usage') .parse(process.argv); \ No newline at end of file From 71f2f644e92590176e7d2432897b07b34f506ac3 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 16:08:04 -0500 Subject: [PATCH 0206/1008] Removing octorun-modern --- octorun-modern/.env.template | 3 -- octorun-modern/.gitignore | 3 -- octorun-modern/index.js | 68 ------------------------------- octorun-modern/package-lock.json | 69 -------------------------------- octorun-modern/package.json | 16 -------- 5 files changed, 159 deletions(-) delete mode 100644 octorun-modern/.env.template delete mode 100644 octorun-modern/.gitignore delete mode 100644 octorun-modern/index.js delete mode 100644 octorun-modern/package-lock.json delete mode 100644 octorun-modern/package.json diff --git a/octorun-modern/.env.template b/octorun-modern/.env.template deleted file mode 100644 index 53bc61631..000000000 --- a/octorun-modern/.env.template +++ /dev/null @@ -1,3 +0,0 @@ -OCTOKIT_CLIENT_ID= -OCTOKIT_CLIENT_SECRET= -OCTOKIT_APP_NAME = \ No newline at end of file diff --git a/octorun-modern/.gitignore b/octorun-modern/.gitignore deleted file mode 100644 index ef4fcce9d..000000000 --- a/octorun-modern/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.env -node_modules -npm-debug.log diff --git a/octorun-modern/index.js b/octorun-modern/index.js deleted file mode 100644 index 246fc0c82..000000000 --- a/octorun-modern/index.js +++ /dev/null @@ -1,68 +0,0 @@ -const readlineSync = require("readline-sync"); -const octokit = require('@octokit/rest')({ - timeout: 0, // 0 means no request timeout - requestMedia: 'application/vnd.github.v3+json', - headers: { - 'user-agent': 'octokit/rest.js v1.2.3' // v1.2.3 will be current version - }, - - // change for custom GitHub Enterprise URL - //host: 'api.github.com', - //pathPrefix: '', - //protocol: 'https', - //port: 443, - - // Node only: advanced request options can be passed as http(s) agent - //agent: undefined - }); - -console.log("NodeJS Path: ", process.argv[0]); - -require("dotenv").config(); - -const clientId = process.env.OCTOKIT_CLIENT_ID; -const clientSecret = process.env.OCTOKIT_CLIENT_SECRET; - -const appName = process.env.OCTORUN_APP_NAME | "octorun"; -let user = process.env.OCTORUN_USER; -const token = process.env.OCTORUN_TOKEN; - -const scopes = ["user", "repo", "gist", "write:public_key"]; - -if(user != null && token != null) -{ - -} -else -{ - user = readlineSync.question('User: '); - - var pwd = readlineSync.question('Password: ', { - hideEchoBack: true - }); - - octokit.authenticate({ - type:"basic", - username:user, - password:pwd - }); - - octokit.authorization.create({ - scopes: scopes, - note: appName, - client_id: clientId, - client_secret: clientSecret - }, function(err, res) { - - console.log("err", err, "res", res); - - if(err) - { - - } - else - { - - } - }); -} diff --git a/octorun-modern/package-lock.json b/octorun-modern/package-lock.json deleted file mode 100644 index a769d5561..000000000 --- a/octorun-modern/package-lock.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "octorun-modern", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@octokit/rest": { - "version": "14.0.9", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-14.0.9.tgz", - "integrity": "sha512-irP9phKfTXEZIcW2R+VNCtGHZJrXMWmSYp6RRfFn4BtAqtDRXF5z9JxCEQlAhNBf6X1koNi5k49tIAAAEJNlVQ==", - "requires": { - "before-after-hook": "1.1.0", - "debug": "3.1.0", - "is-array-buffer": "1.0.0", - "is-stream": "1.1.0", - "lodash": "4.17.5", - "url-template": "2.0.8" - } - }, - "before-after-hook": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-1.1.0.tgz", - "integrity": "sha512-VOMDtYPwLbIncTxNoSzRyvaMxtXmLWLUqr8k5AfC1BzLk34HvBXaQX8snOwQZ4c0aX8aSERqtJSiI9/m2u5kuA==" - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "dotenv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-1.0.0.tgz", - "integrity": "sha1-/cUn/GZBHGHXSjq50Znr+HRTLNQ=" - }, - "is-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-1.0.0.tgz", - "integrity": "sha512-KtzJzWuC1kZQ377GJbEsoBh0LuQh1uaZnQg8oL2LcDkY/Ny8rpAzu21Ls3oph3SEKXbnrLHt3rAUVm28iuEPfw==" - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "readline-sync": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.9.tgz", - "integrity": "sha1-PtqOZfI80qF+YTAbHwADOWr17No=" - }, - "url-template": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", - "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" - } - } -} diff --git a/octorun-modern/package.json b/octorun-modern/package.json deleted file mode 100644 index 7a3648841..000000000 --- a/octorun-modern/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "octorun-modern", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC", - "dependencies": { - "@octokit/rest": "^14.0.9", - "dotenv": "^1.0.0", - "readline-sync": "^1.4.9" - } -} From 70273deb8185a8069bcf3596a6a4938e1cfd7189 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 16:18:24 -0500 Subject: [PATCH 0207/1008] Updating package name --- octorun/package.json | 2 +- octorun/src/octokit.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/octorun/package.json b/octorun/package.json index 2fd6a68ce..2485e16e1 100644 --- a/octorun/package.json +++ b/octorun/package.json @@ -12,7 +12,7 @@ "dependencies": { "commander": "^2.14.1", "dotenv": "^1.0.0", - "octokit-rest-nothing-to-see-here-kthxbye": "^1.0.1", + "octokit-rest-for-node-v0.12": "^1.0.1", "readline-sync": "^1.4.9" } } diff --git a/octorun/src/octokit.js b/octorun/src/octokit.js index f75250491..1cf90b1ac 100644 --- a/octorun/src/octokit.js +++ b/octorun/src/octokit.js @@ -1,4 +1,4 @@ -var Octokit = require('octokit-rest-nothing-to-see-here-kthxbye'); +var Octokit = require('octokit-rest-for-node-v0.12'); var createOctokit = function () { return Octokit({ From 119def35891002c5f03f2cfb27727d26bfeb5d6a Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Thu, 1 Mar 2018 16:19:38 -0500 Subject: [PATCH 0208/1008] Making package version exact --- octorun/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/octorun/package.json b/octorun/package.json index 2485e16e1..dc1ceee3e 100644 --- a/octorun/package.json +++ b/octorun/package.json @@ -12,7 +12,7 @@ "dependencies": { "commander": "^2.14.1", "dotenv": "^1.0.0", - "octokit-rest-for-node-v0.12": "^1.0.1", + "octokit-rest-for-node-v0.12": "1.0.1", "readline-sync": "^1.4.9" } } From effa004d550f5bae8cc0dab5b2a41362737fe163 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 2 Mar 2018 08:39:45 -0500 Subject: [PATCH 0209/1008] Initial hardcoding where to find octorun.js --- .../Application/ApplicationManagerBase.cs | 14 +++++++++----- src/GitHub.Api/Platform/DefaultEnvironment.cs | 1 + src/GitHub.Api/Platform/IEnvironment.cs | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 83283b6af..cdba86a67 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -47,23 +47,26 @@ public void Run(bool firstRun) { Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory); + var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); + var octorunExecPath = applicationDataPath.Combine("octorun", "bin", "octorun"); + var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath(); if (gitExecutablePath != null && gitExecutablePath.FileExists()) // we have a git path { Logger.Trace("Using git install path from settings: {0}", gitExecutablePath); - InitializeEnvironment(gitExecutablePath); + InitializeEnvironment(gitExecutablePath, octorunExecPath); } else // we need to go find git { Logger.Trace("No git path found in settings"); - var initEnvironmentTask = new ActionTask(CancellationToken, (b, path) => InitializeEnvironment(path)) { Affinity = TaskAffinity.UI }; + var initEnvironmentTask = new ActionTask(CancellationToken, (b, path) => InitializeEnvironment(path, octorunExecPath)) { Affinity = TaskAffinity.UI }; var findExecTask = new FindExecTask("git", CancellationToken) .FinallyInUI((b, ex, path) => { if (b && path != null) { Logger.Trace("FindExecTask Success: {0}", path); - InitializeEnvironment(gitExecutablePath); + InitializeEnvironment(gitExecutablePath, octorunExecPath); } else { @@ -72,7 +75,6 @@ public void Run(bool firstRun) } }); - var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); var installDetails = new GitInstallDetails(applicationDataPath, true); var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails); @@ -170,12 +172,14 @@ 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, NPath octorunExecPath) { var afterGitSetup = new ActionTask(CancellationToken, RestartRepository) .ThenInUI(InitializeUI); Environment.GitExecutablePath = gitExecutablePath; + Environment.OctorunExectablePath = octorunExecPath; Environment.User.Initialize(GitClient); if (Environment.IsWindows) diff --git a/src/GitHub.Api/Platform/DefaultEnvironment.cs b/src/GitHub.Api/Platform/DefaultEnvironment.cs index 5536e93a0..f9955a645 100644 --- a/src/GitHub.Api/Platform/DefaultEnvironment.cs +++ b/src/GitHub.Api/Platform/DefaultEnvironment.cs @@ -116,6 +116,7 @@ public string GetEnvironmentVariable(string variable) public NPath SystemCachePath { get; set; } public NPath Path { get { return Environment.GetEnvironmentVariable("PATH").ToNPath(); } } public string NewLine { get { return Environment.NewLine; } } + public NPath OctorunExectablePath { get; set; } private NPath gitExecutablePath; public NPath GitExecutablePath diff --git a/src/GitHub.Api/Platform/IEnvironment.cs b/src/GitHub.Api/Platform/IEnvironment.cs index d37c89ec9..e24572c1b 100644 --- a/src/GitHub.Api/Platform/IEnvironment.cs +++ b/src/GitHub.Api/Platform/IEnvironment.cs @@ -13,6 +13,7 @@ public interface IEnvironment NPath Path { get; } string NewLine { get; } NPath GitExecutablePath { get; set; } + NPath OctorunExectablePath { get; set; } bool IsWindows { get; } bool IsLinux { get; } bool IsMac { get; } From 1b094a146defd80bbd7a26eca042dfd7ff07e54b Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Fri, 2 Mar 2018 12:41:33 -0500 Subject: [PATCH 0210/1008] Starting to call octorun in nodejs --- octorun/src/bin/app-login.js | 6 +- src/GitHub.Api/Application/ApiClient.cs | 15 ++-- .../Application/ApplicationManagerBase.cs | 24 +++--- .../Application/IApplicationManager.cs | 2 - src/GitHub.Api/Authentication/LoginManager.cs | 77 +++++++++++-------- src/GitHub.Api/Platform/DefaultEnvironment.cs | 19 ++++- src/GitHub.Api/Platform/IEnvironment.cs | 3 +- .../Editor/GitHub.Unity/ApplicationManager.cs | 5 -- .../Editor/GitHub.Unity/Misc/Utility.cs | 28 ------- .../Services/AuthenticationService.cs | 4 +- .../GitHub.Unity/UI/AuthenticationView.cs | 2 +- .../Editor/GitHub.Unity/UI/PopupWindow.cs | 2 +- .../Editor/GitHub.Unity/UI/PublishView.cs | 2 +- .../Assets/Editor/GitHub.Unity/UI/Window.cs | 2 +- .../IntegrationTestEnvironment.cs | 2 + 15 files changed, 91 insertions(+), 102 deletions(-) diff --git a/octorun/src/bin/app-login.js b/octorun/src/bin/app-login.js index c0b7bddb2..19f2582fd 100644 --- a/octorun/src/bin/app-login.js +++ b/octorun/src/bin/app-login.js @@ -13,7 +13,7 @@ if (commander.twoFactor) { process.exit(); }, function (err) { console.log(err); - process.exit(-1); + process.exit(); }); } else { @@ -22,9 +22,9 @@ else { process.exit(); }, function () { console.log("Must specify two-factor authentication OTP code."); - process.exit(1); + process.exit(); }, function (err) { console.log(err); - process.exit(-1); + process.exit(); }); } \ No newline at end of file diff --git a/src/GitHub.Api/Application/ApiClient.cs b/src/GitHub.Api/Application/ApiClient.cs index a691c6321..59ea6a55b 100644 --- a/src/GitHub.Api/Application/ApiClient.cs +++ b/src/GitHub.Api/Application/ApiClient.cs @@ -10,7 +10,7 @@ namespace GitHub.Unity { class ApiClient : IApiClient { - public static IApiClient Create(UriString repositoryUrl, IKeychain keychain, IProcessManager processManager, ITaskManager taskManager, NPath loginTool) + public static IApiClient Create(UriString repositoryUrl, IKeychain keychain, IProcessManager processManager, ITaskManager taskManager, NPath nodeJsExecutablePath, NPath octorunScriptPath) { logger.Trace("Creating ApiClient: {0}", repositoryUrl); @@ -19,7 +19,7 @@ public static IApiClient Create(UriString repositoryUrl, IKeychain keychain, IPr return new ApiClient(repositoryUrl, keychain, new GitHubClient(ApplicationConfiguration.ProductHeader, credentialStore, hostAddress.ApiUri), - processManager, taskManager, loginTool); + processManager, taskManager, nodeJsExecutablePath, octorunScriptPath); } private static readonly ILogging logger = LogHelper.GetLogger(); @@ -30,10 +30,10 @@ public static IApiClient Create(UriString repositoryUrl, IKeychain keychain, IPr private readonly IGitHubClient githubClient; private readonly IProcessManager processManager; private readonly ITaskManager taskManager; - private readonly NPath loginTool; + private readonly NPath octorunScriptPath; private readonly ILoginManager loginManager; - public ApiClient(UriString hostUrl, IKeychain keychain, IGitHubClient githubClient, IProcessManager processManager, ITaskManager taskManager, NPath loginTool) + public ApiClient(UriString hostUrl, IKeychain keychain, IGitHubClient githubClient, IProcessManager processManager, ITaskManager taskManager, NPath nodeJsExecutablePath, NPath octorunScriptPath) { Guard.ArgumentNotNull(hostUrl, nameof(hostUrl)); Guard.ArgumentNotNull(keychain, nameof(keychain)); @@ -45,11 +45,12 @@ public ApiClient(UriString hostUrl, IKeychain keychain, IGitHubClient githubClie this.githubClient = githubClient; this.processManager = processManager; this.taskManager = taskManager; - this.loginTool = loginTool; + this.octorunScriptPath = octorunScriptPath; loginManager = new LoginManager(keychain, ApplicationInfo.ClientId, ApplicationInfo.ClientSecret, processManager: processManager, - taskManager: taskManager, - loginTool: loginTool); + taskManager: taskManager, + nodeJsExecutablePath: nodeJsExecutablePath, + octorunScript: octorunScriptPath); } public async Task Logout(UriString host) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index cdba86a67..2d0093808 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -47,26 +47,26 @@ public void Run(bool firstRun) { Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory); - var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); - var octorunExecPath = applicationDataPath.Combine("octorun", "bin", "octorun"); + var octorunScriptPath = Environment.UserCachePath.Combine("octorun", "src", "bin", "app.js"); + Logger.Trace("Using octorunScriptPath: {0}", octorunScriptPath); var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath(); if (gitExecutablePath != null && gitExecutablePath.FileExists()) // we have a git path { Logger.Trace("Using git install path from settings: {0}", gitExecutablePath); - InitializeEnvironment(gitExecutablePath, octorunExecPath); + InitializeEnvironment(gitExecutablePath, octorunScriptPath); } else // we need to go find git { Logger.Trace("No git path found in settings"); - var initEnvironmentTask = new ActionTask(CancellationToken, (b, path) => InitializeEnvironment(path, octorunExecPath)) { Affinity = TaskAffinity.UI }; + var initEnvironmentTask = new ActionTask(CancellationToken, (b, path) => InitializeEnvironment(path, octorunScriptPath)) { Affinity = TaskAffinity.UI }; var findExecTask = new FindExecTask("git", CancellationToken) .FinallyInUI((b, ex, path) => { if (b && path != null) { Logger.Trace("FindExecTask Success: {0}", path); - InitializeEnvironment(gitExecutablePath, octorunExecPath); + InitializeEnvironment(gitExecutablePath, octorunScriptPath); } else { @@ -75,7 +75,7 @@ public void Run(bool firstRun) } }); - var installDetails = new GitInstallDetails(applicationDataPath, true); + var installDetails = new GitInstallDetails(Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(), true); var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails); // if successful, continue with environment initialization, otherwise try to find an existing git installation @@ -172,14 +172,14 @@ 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, NPath octorunExecPath) + /// + private void InitializeEnvironment(NPath gitExecutablePath, NPath octorunScriptPath) { var afterGitSetup = new ActionTask(CancellationToken, RestartRepository) .ThenInUI(InitializeUI); Environment.GitExecutablePath = gitExecutablePath; - Environment.OctorunExectablePath = octorunExecPath; + Environment.OctorunScriptPath = octorunScriptPath; Environment.User.Initialize(GitClient); if (Environment.IsWindows) @@ -221,11 +221,6 @@ protected virtual void Dispose(bool disposing) } } - public virtual NPath GetTool(string tool) - { - return null; - } - public void Dispose() { Dispose(true); @@ -243,7 +238,6 @@ public void Dispose() public ISettings SystemSettings { get; protected set; } public ISettings UserSettings { get; protected set; } public IUsageTracker UsageTracker { get; protected set; } - public NPath LoginTool => GetTool("octorun.exe"); protected TaskScheduler UIScheduler { get; private set; } protected SynchronizationContext SynchronizationContext { get; private set; } protected IRepositoryManager RepositoryManager { get { return repositoryManager; } } diff --git a/src/GitHub.Api/Application/IApplicationManager.cs b/src/GitHub.Api/Application/IApplicationManager.cs index 004c4e7d9..fd59878a8 100644 --- a/src/GitHub.Api/Application/IApplicationManager.cs +++ b/src/GitHub.Api/Application/IApplicationManager.cs @@ -17,11 +17,9 @@ public interface IApplicationManager : IDisposable ITaskManager TaskManager { get; } IGitClient GitClient { get; } IUsageTracker UsageTracker { get; } - NPath LoginTool { get; } void Run(bool firstRun); void RestartRepository(); ITask InitializeRepository(); - NPath GetTool(string tool); } } \ No newline at end of file diff --git a/src/GitHub.Api/Authentication/LoginManager.cs b/src/GitHub.Api/Authentication/LoginManager.cs index eae7156ab..fd83383d5 100644 --- a/src/GitHub.Api/Authentication/LoginManager.cs +++ b/src/GitHub.Api/Authentication/LoginManager.cs @@ -30,7 +30,8 @@ class LoginManager : ILoginManager private readonly string fingerprint; private readonly IProcessManager processManager; private readonly ITaskManager taskManager; - private readonly NPath loginTool; + private readonly NPath nodeJsExecutablePath; + private readonly NPath octorunScript; /// /// Initializes a new instance of the class. @@ -42,16 +43,15 @@ class LoginManager : ILoginManager /// The machine fingerprint. /// /// - /// - /// The cache in which to store login details. - /// The handler for 2FA challenges. + /// + /// public LoginManager( IKeychain keychain, string clientId, string clientSecret, string authorizationNote = null, string fingerprint = null, - IProcessManager processManager = null, ITaskManager taskManager = null, NPath loginTool = null) + IProcessManager processManager = null, ITaskManager taskManager = null, NPath nodeJsExecutablePath = null, NPath octorunScript = null) { Guard.ArgumentNotNull(keychain, nameof(keychain)); Guard.ArgumentNotNullOrWhiteSpace(clientId, nameof(clientId)); @@ -64,7 +64,8 @@ public LoginManager( this.fingerprint = fingerprint; this.processManager = processManager; this.taskManager = taskManager; - this.loginTool = loginTool; + this.nodeJsExecutablePath = nodeJsExecutablePath; + this.octorunScript = octorunScript; } /// @@ -258,11 +259,11 @@ private async Task TryLogin( string password ) { - logger.Info("Login Username:{0} {1}", username, loginTool); + logger.Info("Login Username:{0} {1}", username, octorunScript); ApplicationAuthorization auth = null; - var loginTask = new SimpleListProcessTask(taskManager.Token, loginTool, $"login --host={host}"); - loginTask.Configure(processManager, workingDirectory: loginTool.Parent, withInput: true); + var loginTask = new SimpleListProcessTask(taskManager.Token, nodeJsExecutablePath, $"{octorunScript} login"); + loginTask.Configure(processManager, workingDirectory: octorunScript.Parent.Parent.Parent, withInput: true); loginTask.OnStartProcess += proc => { proc.StandardInput.WriteLine(username); @@ -270,31 +271,39 @@ string password proc.StandardInput.Close(); }; var ret = await loginTask.StartAwait(); - if (ret.Count == 0) + + foreach (var result in ret) { - throw new Exception("Authentication failed"); + logger.Trace(result); } - // success - else if (ret.Count == 1) - { - auth = new ApplicationAuthorization(ret[0]); - } - else - { - if (ret[0] == "2fa") - { - keychain.SetToken(host, ret[1]); - await keychain.Save(host); - throw new TwoFactorRequiredException(TwoFactorType.Unknown); - } - else if (ret[0] == "locked") - { - throw new LoginAttemptsExceededException(null, null); - } - else - throw new Exception("Authentication failed"); - } - return auth; + + throw new Exception("Authentication failed"); + + // if (ret.Count == 0) + // { + // throw new Exception("Authentication failed"); + // } + // // success + // else if (ret.Count == 1) + // { + // auth = new ApplicationAuthorization(ret[0]); + // } + // else + // { + // if (ret[0] == "Must specify two-factor authentication OTP code.") + // { + // keychain.SetToken(host, ret[1]); + // await keychain.Save(host); + // throw new TwoFactorRequiredException(TwoFactorType.Unknown); + // } + // else if (ret[0] == "locked") + // { + // throw new LoginAttemptsExceededException(null, null); + // } + // else + // throw new Exception("Authentication failed"); + // } + // return auth; } private async Task TryContinueLogin( @@ -308,8 +317,8 @@ string code logger.Info("Continue Username:{0}", username); ApplicationAuthorization auth = null; - var loginTask = new SimpleListProcessTask(taskManager.Token, loginTool, $"login --host={host} --2fa"); - loginTask.Configure(processManager, workingDirectory: loginTool.Parent, withInput: true); + var loginTask = new SimpleListProcessTask(taskManager.Token, nodeJsExecutablePath, $"{octorunScript} login --twoFactor"); + loginTask.Configure(processManager, workingDirectory: nodeJsExecutablePath.Parent, withInput: true); loginTask.OnStartProcess += proc => { proc.StandardInput.WriteLine(username); diff --git a/src/GitHub.Api/Platform/DefaultEnvironment.cs b/src/GitHub.Api/Platform/DefaultEnvironment.cs index f9955a645..24056d69d 100644 --- a/src/GitHub.Api/Platform/DefaultEnvironment.cs +++ b/src/GitHub.Api/Platform/DefaultEnvironment.cs @@ -116,7 +116,7 @@ public string GetEnvironmentVariable(string variable) public NPath SystemCachePath { get; set; } public NPath Path { get { return Environment.GetEnvironmentVariable("PATH").ToNPath(); } } public string NewLine { get { return Environment.NewLine; } } - public NPath OctorunExectablePath { get; set; } + public NPath OctorunScriptPath { get; set; } private NPath gitExecutablePath; public NPath GitExecutablePath @@ -132,6 +132,23 @@ public NPath GitExecutablePath } } + private NPath nodeJsExecutablePath; + + public NPath NodeJsExecutablePath + { + get + { + if (nodeJsExecutablePath == null) + { + nodeJsExecutablePath = IsWindows + ? UnityApplication.Parent.Combine("Data", "Tools", "nodejs", "node.exe") + : UnityApplication.Combine("Contents", "Tools", "nodejs", "node"); + } + + return nodeJsExecutablePath; + } + } + public NPath GitInstallPath { get; private set; } public NPath RepositoryPath { get; private set; } diff --git a/src/GitHub.Api/Platform/IEnvironment.cs b/src/GitHub.Api/Platform/IEnvironment.cs index e24572c1b..59f7e0289 100644 --- a/src/GitHub.Api/Platform/IEnvironment.cs +++ b/src/GitHub.Api/Platform/IEnvironment.cs @@ -13,7 +13,8 @@ public interface IEnvironment NPath Path { get; } string NewLine { get; } NPath GitExecutablePath { get; set; } - NPath OctorunExectablePath { get; set; } + NPath NodeJsExecutablePath { get; } + NPath OctorunScriptPath { get; set; } bool IsWindows { get; } bool IsLinux { get; } bool IsMac { get; } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs index 47780c415..c5fcfd00c 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationManager.cs @@ -21,11 +21,6 @@ public ApplicationManager(IMainThreadSynchronizationContext synchronizationConte Initialize(); } - public override NPath GetTool(string tool) - { - return Utility.GetTool(tool); - } - protected override void SetupMetrics() { SetupMetrics(Environment.UnityVersion, ApplicationCache.Instance.FirstRun); diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs index 7bd4e70ad..91f2a9400 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs @@ -50,34 +50,6 @@ public static Texture2D GetTextureFromColor(Color color) return result; } - - public static NPath GetTool(string tool) - { - var outfile = EntryPoint.Environment.UserCachePath.Combine("tools", tool); - outfile.EnsureParentDirectoryExists(); - - if (tool == "octorun.exe") - { - GetTool("Mono.Options.dll"); - GetTool("GitHub.Logging.dll"); - GetTool("Octokit.dll"); - } - - if (outfile.Exists()) - return outfile; - - var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("GitHub.Unity.Tools." + tool); - if (stream != null) - { - var targetFile = new FileInfo(outfile); - using (var outstream = targetFile.OpenWrite()) - { - ZipHelper.Copy(stream, outstream, 8192, stream.Length, null, 0); - } - } - LogHelper.GetLogger().Debug(outfile); - return outfile; - } } static class StreamExtensions diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Services/AuthenticationService.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Services/AuthenticationService.cs index c627615ee..73b38da86 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Services/AuthenticationService.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Services/AuthenticationService.cs @@ -8,9 +8,9 @@ class AuthenticationService private LoginResult loginResultData; - public AuthenticationService(UriString host, IKeychain keychain) + public AuthenticationService(UriString host, IKeychain keychain, NPath nodeJsExecutablePath, NPath octorunExecutablePath) { - client = ApiClient.Create(host, keychain, EntryPoint.ApplicationManager.ProcessManager, EntryPoint.ApplicationManager.TaskManager, EntryPoint.ApplicationManager.LoginTool); + client = ApiClient.Create(host, keychain, EntryPoint.ApplicationManager.ProcessManager, EntryPoint.ApplicationManager.TaskManager, nodeJsExecutablePath, octorunExecutablePath); } public void Login(string username, string password, Action twofaRequired, Action authResult) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs index c7795c05a..fd3dc96e7 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationView.cs @@ -256,7 +256,7 @@ private AuthenticationService AuthenticationService host = UriString.ToUriString(HostAddress.GitHubDotComHostAddress.WebUri); } - AuthenticationService = new AuthenticationService(host, Platform.Keychain); + AuthenticationService = new AuthenticationService(host, Platform.Keychain, Environment.NodeJsExecutablePath, Environment.OctorunScriptPath); } return authenticationService; } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PopupWindow.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PopupWindow.cs index 1fdd82047..f2a15fa89 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PopupWindow.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PopupWindow.cs @@ -198,7 +198,7 @@ public IApiClient Client host = UriString.ToUriString(HostAddress.GitHubDotComHostAddress.WebUri); } - client = ApiClient.Create(host, Platform.Keychain, Manager.ProcessManager, TaskManager, Manager.LoginTool); + client = ApiClient.Create(host, Platform.Keychain, Manager.ProcessManager, TaskManager, Environment.NodeJsExecutablePath, Environment.OctorunScriptPath); } return client; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs index 4ff5cac35..29d1505cc 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/PublishView.cs @@ -53,7 +53,7 @@ public IApiClient Client host = UriString.ToUriString(HostAddress.GitHubDotComHostAddress.WebUri); } - client = ApiClient.Create(host, Platform.Keychain, Manager.ProcessManager, TaskManager, Manager.LoginTool); + client = ApiClient.Create(host, Platform.Keychain, Manager.ProcessManager, TaskManager, Environment.NodeJsExecutablePath, Environment.OctorunScriptPath); } return client; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs index 3f73c7107..b4cf889c1 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs @@ -451,7 +451,7 @@ private void SignOut(object obj) host = UriString.ToUriString(HostAddress.GitHubDotComHostAddress.WebUri); } - var apiClient = ApiClient.Create(host, Platform.Keychain, null, null, null); + var apiClient = ApiClient.Create(host, Platform.Keychain, null, null, null, null); apiClient.Logout(host); } diff --git a/src/tests/IntegrationTests/IntegrationTestEnvironment.cs b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs index a99d636d1..7071f260a 100644 --- a/src/tests/IntegrationTests/IntegrationTestEnvironment.cs +++ b/src/tests/IntegrationTests/IntegrationTestEnvironment.cs @@ -104,6 +104,8 @@ public NPath GitExecutablePath } } + public NPath OctorunScriptPath { get; set; } + public bool IsWindows => defaultEnvironment.IsWindows; public bool IsLinux => defaultEnvironment.IsLinux; public bool IsMac => defaultEnvironment.IsMac; From 7873cd26a664e49758c621739698eb94b51168af Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 2 Mar 2018 18:52:05 +0000 Subject: [PATCH 0211/1008] Make downloading parallel and fix concurrent threading Make the downloads in pairs (file and md5) in a downloader class that can run them all parallel. I kept getting deadlocks and it's something to do with how the concurrent scheduler is set up, so replaced it with a scheduler that just fires a thread per task and does nothing smart about it. --- src/GitHub.Api/GitHub.Api.csproj | 1 + src/GitHub.Api/IO/NiceIO.cs | 5 + src/GitHub.Api/IO/Utils.cs | 65 +-- src/GitHub.Api/Installer/GitInstaller.cs | 49 +-- src/GitHub.Api/Installer/UnzipTask.cs | 4 +- src/GitHub.Api/Managers/Downloader.cs | 216 ++++++++++ src/GitHub.Api/Tasks/ActionTask.cs | 19 + .../Tasks/ConcurrentExclusiveInterleave.cs | 52 ++- src/GitHub.Api/Tasks/DownloadTask.cs | 106 +---- src/GitHub.Api/Tasks/TaskBase.cs | 20 +- src/GitHub.Api/Tasks/TaskManager.cs | 4 +- .../Download/DownloadTaskTests.cs | 384 +++++++++++++----- src/tests/IntegrationTests/UnzipTaskTests.cs | 46 +-- src/tests/TaskSystemIntegrationTests/Tests.cs | 4 +- src/tests/TestWebServer/HttpServer.cs | 6 +- 15 files changed, 636 insertions(+), 345 deletions(-) create mode 100644 src/GitHub.Api/Managers/Downloader.cs diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 6b45e1234..073f5da6d 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -118,6 +118,7 @@ + diff --git a/src/GitHub.Api/IO/NiceIO.cs b/src/GitHub.Api/IO/NiceIO.cs index eab97ee5c..27e59377a 100644 --- a/src/GitHub.Api/IO/NiceIO.cs +++ b/src/GitHub.Api/IO/NiceIO.cs @@ -1074,6 +1074,11 @@ public static NPath Resolve(this NPath path) return new NPath(Mono.Unix.UnixPath.GetCompleteRealPath(path.ToString())); } + + public static string CalculateMD5(this NPath path) + { + return NPath.FileSystem.CalculateFileMD5(path); + } } public enum SlashMode diff --git a/src/GitHub.Api/IO/Utils.cs b/src/GitHub.Api/IO/Utils.cs index 2c0621906..34fcccdf0 100644 --- a/src/GitHub.Api/IO/Utils.cs +++ b/src/GitHub.Api/IO/Utils.cs @@ -82,68 +82,11 @@ public static bool Copy(Stream source, Stream destination, return success; } - - public static bool Download(ILogging logger, UriString url, - Stream destinationStream, - Func onProgress) + public static bool VerifyFileIntegrity(NPath file, NPath md5file) { - long bytes = destinationStream.Length; - - var expectingResume = bytes > 0; - - var webRequest = (HttpWebRequest)WebRequest.Create(url); - - if (expectingResume) - { - // classlib for 3.5 doesn't take long overloads... - webRequest.AddRange((int)bytes); - } - - webRequest.Method = "GET"; - webRequest.Timeout = ApplicationConfiguration.WebTimeout; - - if (expectingResume) - logger.Trace($"Resuming download of {url}"); - else - logger.Trace($"Downloading {url}"); - - using (var webResponse = (HttpWebResponse) webRequest.GetResponseWithoutException()) - { - var httpStatusCode = webResponse.StatusCode; - logger.Trace($"Downloading {url} StatusCode:{(int)webResponse.StatusCode}"); - - if (expectingResume && httpStatusCode == HttpStatusCode.RequestedRangeNotSatisfiable) - { - onProgress(bytes, bytes); - return true; - } - - if (!(httpStatusCode == HttpStatusCode.OK || httpStatusCode == HttpStatusCode.PartialContent)) - { - return false; - } - - if (expectingResume && httpStatusCode == HttpStatusCode.OK) - { - expectingResume = false; - destinationStream.Seek(0, SeekOrigin.Begin); - } - - var responseLength = webResponse.ContentLength; - if (expectingResume) - { - if (!onProgress(bytes, bytes + responseLength)) - return false; - } - - using (var responseStream = webResponse.GetResponseStream()) - { - return Copy(responseStream, destinationStream, responseLength, - progress: (totalRead, timeToFinish) => { - return onProgress(totalRead, responseLength); - }); - } - } + var expected = md5file.ReadAllText(); + var actual = file.CalculateMD5(); + return expected.Equals(actual, StringComparison.InvariantCultureIgnoreCase); } } } \ No newline at end of file diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index a1fdc3a56..c8e9e28c6 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -1,5 +1,6 @@ using System; using System.Threading; +using System.Threading.Tasks; using GitHub.Logging; namespace GitHub.Unity @@ -116,22 +117,27 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) return; } - var task = new FuncTask(cancellationToken, () => + var isGitExtractedTask = new FuncTask(cancellationToken, () => { if (!IsGitExtracted()) - { - Logger.Trace("SetupGitIfNeeded: Skipped"); - throw new Exception(); - } + return null; + Logger.Trace("SetupGitIfNeeded: Skipped"); return installDetails.GitExecutablePath; }); - var extractTask = ExtractPortableGit(); - extractTask.Then(onSuccess, TaskRunOptions.OnSuccess, taskIsTopOfChain: true); - extractTask.Then(onFailure, TaskRunOptions.OnFailure, taskIsTopOfChain: true); + isGitExtractedTask.OnEnd += (t, res, _, __) => + { + if (res == null) + { + var extractTask = ExtractPortableGit(); + extractTask.Then(onSuccess, TaskRunOptions.OnSuccess, taskIsTopOfChain: true); + extractTask.Then(onFailure, TaskRunOptions.OnFailure, taskIsTopOfChain: true); + t.Then(extractTask); + } + else + t.Then(onSuccess); + }; - task.Then(onSuccess, TaskRunOptions.OnSuccess, taskIsTopOfChain: true); - task.Then(extractTask, TaskRunOptions.OnFailure, taskIsTopOfChain: true); - task.Start(); + isGitExtractedTask.Start(); } private FuncTask ExtractPortableGit() @@ -157,6 +163,7 @@ private FuncTask CreateUnzipTasks(NPath gitExtractPath, NPath gitLfsExtra environment.FileSystem, GitInstallDetails.GitExtractedMD5); var unzipGitLfsTask = new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper, environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5); + var moveGitTask = new FuncTask(cancellationToken, () => MoveGitAndLfs(gitExtractPath, gitLfsExtractPath, tempZipExtractPath)); return unzipGitTask .Then(unzipGitLfsTask) @@ -191,24 +198,12 @@ private ITask CreateDownloadTask() gitArchiveFilePath = installDetails.PluginDataPath.Combine("git.zip"); gitLfsArchivePath = installDetails.PluginDataPath.Combine("git-lfs.zip"); - var downloadGitMd5Task = new DownloadTextTask(TaskManager.Instance.Token, environment.FileSystem, - installDetails.GitZipMd5Url, installDetails.PluginDataPath); - - var downloadGitTask = new DownloadTask(TaskManager.Instance.Token, environment.FileSystem, - installDetails.GitZipUrl, installDetails.PluginDataPath); - - var downloadGitLfsMd5Task = new DownloadTextTask(TaskManager.Instance.Token, environment.FileSystem, - installDetails.GitLfsZipMd5Url, installDetails.PluginDataPath); + var downloader = new Downloader(); - var downloadGitLfsTask = new DownloadTask(TaskManager.Instance.Token, environment.FileSystem, - installDetails.GitLfsZipUrl, installDetails.PluginDataPath); + downloader.QueueDownload(installDetails.GitZipUrl, installDetails.GitZipMd5Url, installDetails.PluginDataPath); + downloader.QueueDownload(installDetails.GitLfsZipUrl, installDetails.GitLfsZipMd5Url, installDetails.PluginDataPath); - return - downloadGitMd5Task.Then((b, s) => { downloadGitTask.ValidationHash = s; }) - .Then(downloadGitTask) - .Then(downloadGitLfsMd5Task) - .Then((b, s) => { downloadGitLfsTask.ValidationHash = s; }) - .Then(downloadGitLfsTask); + return downloader; } private bool IsGitExtracted() diff --git a/src/GitHub.Api/Installer/UnzipTask.cs b/src/GitHub.Api/Installer/UnzipTask.cs index 822d64e02..4e0eadb43 100644 --- a/src/GitHub.Api/Installer/UnzipTask.cs +++ b/src/GitHub.Api/Installer/UnzipTask.cs @@ -78,7 +78,7 @@ protected virtual void RunUnzip(bool success) if (expectedMD5 != null) { var calculatedMD5 = fileSystem.CalculateFolderMD5(extractedPath); - success = !calculatedMD5.Equals(expectedMD5, StringComparison.InvariantCultureIgnoreCase); + success = calculatedMD5.Equals(expectedMD5, StringComparison.InvariantCultureIgnoreCase); if (!success) { extractedPath.DeleteIfExists(); @@ -100,7 +100,7 @@ protected virtual void RunUnzip(bool success) if (!success) { Token.ThrowIfCancellationRequested(); - throw new UnzipException("Error downloading file", exception); + throw new UnzipException("Error unzipping file", exception); } } protected int RetryCount { get; } diff --git a/src/GitHub.Api/Managers/Downloader.cs b/src/GitHub.Api/Managers/Downloader.cs new file mode 100644 index 000000000..735862194 --- /dev/null +++ b/src/GitHub.Api/Managers/Downloader.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using GitHub.Logging; +using System.Linq; + +namespace GitHub.Unity +{ + class DownloadData + { + public UriString Url { get; } + public NPath File { get; } + public DownloadData(UriString url, NPath file) + { + this.Url = url; + this.File = file; + } + } + + class Downloader : FuncListTask + { + public event Action DownloadStart; + public event Action DownloadComplete; + public event Action DownloadFailed; + + private readonly List downloaders = new List(); + + public Downloader() : base(TaskManager.Instance.Token, RunDownloaders) + {} + + public void QueueDownload(UriString url, UriString md5Url, NPath targetDirectory) + { + var pairDownloader = new PairDownloader(); + pairDownloader.QueueDownload(url, md5Url, targetDirectory); + downloaders.Add(pairDownloader); + } + + private static List RunDownloaders(bool success, FuncListTask source) + { + Downloader self = (Downloader)source; + List result = null; + var listOfTasks = new List>(); + foreach (var downloader in self.downloaders) + { + downloader.DownloadStart += self.DownloadStart; + downloader.DownloadComplete += self.DownloadComplete; + downloader.DownloadFailed += self.DownloadFailed; + listOfTasks.Add(downloader.Run()); + } + var res = TaskEx.WhenAll(listOfTasks).Result; + if (res != null) + result = new List(res); + return result; + } + + class PairDownloader + { + public event Action DownloadStart; + public event Action DownloadComplete; + public event Action DownloadFailed; + + private readonly List> queuedTasks = new List>(); + private readonly TaskCompletionSource aggregateDownloads = new TaskCompletionSource(); + private readonly IFileSystem fs; + private readonly CancellationToken cancellationToken; + + private volatile int finishedTaskCount; + private volatile bool isSuccessful = true; + private volatile Exception exception; + + public PairDownloader() + { + fs = NPath.FileSystem; + cancellationToken = TaskManager.Instance.Token; + DownloadComplete += d => aggregateDownloads.TrySetResult(d); + DownloadFailed += (_, e) => aggregateDownloads.TrySetException(e); + } + + public Task Run() + { + foreach (var task in queuedTasks) + task.Start(); + return aggregateDownloads.Task; + } + + public Task QueueDownload(UriString url, UriString md5Url, NPath targetDirectory) + { + var destinationFile = targetDirectory.Combine(url.Filename); + var destinationMd5 = targetDirectory.Combine(md5Url.Filename); + var result = new DownloadData(url, destinationFile); + + Action, NPath, bool, Exception> verifyDownload = (t, res, success, ex) => + { + var count = Interlocked.Increment(ref finishedTaskCount); + isSuccessful &= success; + if (!success) + exception = ex; + if (count == queuedTasks.Count) + { + if (!isSuccessful) + { + DownloadFailed(result, exception); + } + else + { + if (!Utils.VerifyFileIntegrity(destinationFile, destinationMd5)) + { + destinationMd5.Delete(); + destinationFile.Delete(); + DownloadFailed(result, new DownloadException($"Verification of {url} failed")); + } + else + DownloadComplete(result); + } + } + }; + + var md5Exists = destinationMd5.FileExists(); + var fileExists = destinationFile.FileExists(); + + if (!md5Exists) + { + destinationMd5.DeleteIfExists(); + var md5Download = new DownloadTask(cancellationToken, fs, md5Url, targetDirectory) + .Catch(e => DownloadFailed(result, e)); + md5Download.OnEnd += verifyDownload; + 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; + queuedTasks.Add(fileDownload); + } + + if (fileExists && md5Exists) + { + var verification = new FuncTask(cancellationToken, () => destinationFile); + verification.OnEnd += verifyDownload; + queuedTasks.Add(verification); + } + return aggregateDownloads.Task; + } + } + + public static bool Download(ILogging logger, UriString url, + Stream destinationStream, + Func onProgress) + { + long bytes = destinationStream.Length; + + var expectingResume = bytes > 0; + + var webRequest = (HttpWebRequest)WebRequest.Create(url); + + if (expectingResume) + { + // classlib for 3.5 doesn't take long overloads... + webRequest.AddRange((int)bytes); + } + + webRequest.Method = "GET"; + webRequest.Timeout = ApplicationConfiguration.WebTimeout; + + if (expectingResume) + logger.Trace($"Resuming download of {url}"); + else + logger.Trace($"Downloading {url}"); + + using (var webResponse = (HttpWebResponse)webRequest.GetResponseWithoutException()) + { + var httpStatusCode = webResponse.StatusCode; + logger.Trace($"Downloading {url} StatusCode:{(int)webResponse.StatusCode}"); + + if (expectingResume && httpStatusCode == HttpStatusCode.RequestedRangeNotSatisfiable) + { + onProgress(bytes, bytes); + return true; + } + + if (!(httpStatusCode == HttpStatusCode.OK || httpStatusCode == HttpStatusCode.PartialContent)) + { + return false; + } + + if (expectingResume && httpStatusCode == HttpStatusCode.OK) + { + expectingResume = false; + destinationStream.Seek(0, SeekOrigin.Begin); + } + + var responseLength = webResponse.ContentLength; + if (expectingResume) + { + if (!onProgress(bytes, bytes + responseLength)) + return false; + } + + using (var responseStream = webResponse.GetResponseStream()) + { + return Utils.Copy(responseStream, destinationStream, responseLength, + progress: (totalRead, timeToFinish) => + { + return onProgress(totalRead, responseLength); + }); + } + } + } + } +} diff --git a/src/GitHub.Api/Tasks/ActionTask.cs b/src/GitHub.Api/Tasks/ActionTask.cs index be0dd6790..abe89bbd9 100644 --- a/src/GitHub.Api/Tasks/ActionTask.cs +++ b/src/GitHub.Api/Tasks/ActionTask.cs @@ -280,6 +280,7 @@ protected override TResult RunWithData(bool success, T previousResult) class FuncListTask : DataTaskBase> { protected Func> Callback { get; } + protected Func, List> CallbackWithSelf { get; } protected Func> CallbackWithException { get; } public FuncListTask(CancellationToken token, Func> action) @@ -296,6 +297,13 @@ public FuncListTask(CancellationToken token, Func> acti this.CallbackWithException = action; } + public FuncListTask(CancellationToken token, Func, List> action) + : base(token) + { + Guard.ArgumentNotNull(action, "action"); + this.CallbackWithSelf = action; + } + public FuncListTask(Task> task) : base(task) { } @@ -312,12 +320,23 @@ protected override List RunWithReturn(bool success) { result = Callback(success); } + else if (CallbackWithSelf != null) + { + result = CallbackWithSelf(success, this); + } else if (CallbackWithException != null) { var thrown = GetThrownException(); result = CallbackWithException(success, thrown); } } + catch (AggregateException ex) + { + var e = ex.GetBaseException(); + Errors = e.Message; + if (!RaiseFaultHandlers(e)) + throw e; + } catch (Exception ex) { Errors = ex.Message; diff --git a/src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs b/src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs index 8d14887f4..47e2cd871 100644 --- a/src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs +++ b/src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs @@ -1,12 +1,19 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; namespace GitHub.Unity { + public interface ITaskScheduler + { + Queue Tasks { get; } + void ExecuteTask(Task task); + } + class TaskSchedulerExcludingThread : TaskScheduler { private static ParameterizedThreadStart longRunningThreadWork = new ParameterizedThreadStart(LongRunningThreadWork); @@ -91,7 +98,7 @@ public sealed class ConcurrentExclusiveInterleave /// Synchronizes all activity in this type and its generated schedulers. private readonly object internalLock; /// The scheduler used to queue and execute "reader" tasks that may run concurrently with other readers. - private readonly ConcurrentExclusiveTaskScheduler concurrentTaskScheduler; + private readonly ITaskScheduler concurrentTaskScheduler; /// Whether the exclusive processing of a task should include all of its children as well. private readonly bool exclusiveProcessingIncludesChildren; /// The scheduler used to queue and execute "writer" tasks that must run exclusively while no other tasks for this interleave are running. @@ -121,7 +128,8 @@ public ConcurrentExclusiveInterleave(bool exclusiveProcessingIncludesChildren) // Create the state for this interleave internalLock = new object(); this.exclusiveProcessingIncludesChildren = exclusiveProcessingIncludesChildren; - concurrentTaskScheduler = new ConcurrentExclusiveTaskScheduler(this, new Queue(), interleaveTaskScheduler.MaximumConcurrencyLevel); + //concurrentTaskScheduler = new ConcurrentExclusiveTaskScheduler(this, new Queue(), interleaveTaskScheduler.MaximumConcurrencyLevel); + concurrentTaskScheduler = new ThreadPerTaskScheduler(); exclusiveTaskScheduler = new ConcurrentExclusiveTaskScheduler(this, new Queue(), 1); } @@ -150,6 +158,8 @@ internal void NotifyOfNewWork() /// This has been separated out into its own method to improve the Parallel Tasks window experience. private void ConcurrentExclusiveInterleaveProcessor() { + Logging.LogHelper.GetLogger().Trace("ConcurrentExclusiveInterleaveProcessor"); + if (token.IsCancellationRequested) return; interleaveTaskScheduler.ThreadToExclude = Thread.CurrentThread.ManagedThreadId; @@ -262,7 +272,7 @@ private IEnumerable GetExclusiveTasks() /// Gets a TaskScheduler that can be used to schedule tasks to this interleave /// that may run concurrently with other tasks on this interleave. /// - public TaskScheduler ConcurrentTaskScheduler + public ITaskScheduler ConcurrentTaskScheduler { get { return concurrentTaskScheduler; } } @@ -330,7 +340,7 @@ public Task InterleaveTask /// /// A scheduler shim used to queue tasks to the interleave and execute those tasks on request of the interleave. /// - private class ConcurrentExclusiveTaskScheduler : TaskScheduler + private class ConcurrentExclusiveTaskScheduler : TaskScheduler, ITaskScheduler { /// The parent interleave. private readonly ConcurrentExclusiveInterleave interleave; @@ -389,7 +399,7 @@ protected override IEnumerable GetScheduledTasks() /// Executes a task on this scheduler. /// The task to be executed. - internal void ExecuteTask(Task task) + public void ExecuteTask(Task task) { var isProcessingTaskOnCurrentThread = this.processingTaskOnCurrentThread.Value; if (!isProcessingTaskOnCurrentThread) this.processingTaskOnCurrentThread.Value = true; @@ -413,7 +423,37 @@ public override int MaximumConcurrencyLevel } /// Gets the queue of tasks for this scheduler. - internal Queue Tasks { get; } + public Queue Tasks { get; } + } + } + + /// Provides a task scheduler that dedicates a thread per task. + public class ThreadPerTaskScheduler : TaskScheduler, ITaskScheduler + { + /// Gets the tasks currently scheduled to this scheduler. + /// This will always return an empty enumerable, as tasks are launched as soon as they're queued. + protected override IEnumerable GetScheduledTasks() { return Enumerable.Empty(); } + public Queue Tasks { get; } = new Queue(); + + /// Starts a new thread to process the provided task. + /// The task to be executed. + protected override void QueueTask(Task task) + { + new Thread(() => TryExecuteTask(task)) { IsBackground = true }.Start(); + } + + /// Runs the provided task on the current thread. + /// The task to be executed. + /// Ignored. + /// Whether the task could be executed on the current thread. + protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) + { + return TryExecuteTask(task); + } + + public void ExecuteTask(Task task) + { + TryExecuteTask(task); } } } diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index 934c1d757..b253c0ec8 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Net; -using System.Text; using System.Threading; namespace GitHub.Unity @@ -26,7 +25,7 @@ public static WebResponse GetResponseWithoutException(this WebRequest request) } } - class DownloadTask : TaskBase + class DownloadTask : TaskBase { protected readonly IFileSystem fileSystem; @@ -34,11 +33,10 @@ public DownloadTask(CancellationToken token, IFileSystem fileSystem, UriString url, NPath targetDirectory = null, string filename = null, - string validationHash = null, int retryCount = 0) + int retryCount = 0) : base(token) { this.fileSystem = fileSystem; - ValidationHash = validationHash; RetryCount = retryCount; Url = url; Filename = filename ?? url.Filename; @@ -51,7 +49,7 @@ protected string BaseRunWithReturn(bool success) return base.RunWithReturn(success); } - protected override string RunWithReturn(bool success) + protected override NPath RunWithReturn(bool success) { var result = base.RunWithReturn(success); @@ -83,70 +81,36 @@ protected override string RunWithReturn(bool success) /// /// /// - protected virtual string RunDownload(bool success) + protected virtual NPath RunDownload(bool success) { Exception exception = null; var attempts = 0; bool result = false; + var partialFile = TargetDirectory.Combine(Filename + ".partial"); do { + exception = null; + if (Token.IsCancellationRequested) break; - exception = null; - try { Logger.Trace($"Download of {Url} to {Destination} Attempt {attempts + 1} of {RetryCount + 1}"); - var fileExistsAndValid = false; - if (Destination.FileExists()) + using (var destinationStream = fileSystem.OpenWrite(partialFile, FileMode.Append)) { - if (ValidationHash == null) - { - Destination.Delete(); - } - else - { - var md5 = fileSystem.CalculateFileMD5(Destination); - result = md5.Equals(ValidationHash, StringComparison.CurrentCultureIgnoreCase); - - if (result) + result = Downloader.Download(Logger, Url, destinationStream, + (value, total) => { - Logger.Trace($"Download previously exists & confirmed {md5}"); - fileExistsAndValid = true; - } - } + UpdateProgress(value, total); + return !Token.IsCancellationRequested; + }); } - if (!fileExistsAndValid) + if (result) { - using (var destinationStream = fileSystem.OpenWrite(Destination, FileMode.Append)) - { - result = Utils.Download(Logger, Url, destinationStream, - (value, total) => - { - UpdateProgress(value, total); - return !Token.IsCancellationRequested; - }); - } - - if (result && ValidationHash != null) - { - var md5 = fileSystem.CalculateFileMD5(Destination); - result = md5.Equals(ValidationHash, StringComparison.CurrentCultureIgnoreCase); - - if (!result) - { - Logger.Warning($"Downloaded MD5 {md5} does not match {ValidationHash}. Deleting {Destination}."); - fileSystem.FileDelete(TargetDirectory); - } - else - { - Logger.Trace($"Download confirmed {md5}"); - break; - } - } + partialFile.Move(Destination); } } catch (Exception ex) @@ -177,8 +141,6 @@ public override string ToString() public NPath Destination { get { return TargetDirectory?.Combine(Filename); } } - public string ValidationHash { get; set; } - protected int RetryCount { get; } } @@ -190,42 +152,4 @@ public DownloadException(string message) : base(message) public DownloadException(string message, Exception innerException) : base(message, innerException) { } } - - class DownloadTextTask : DownloadTask - { - public DownloadTextTask(CancellationToken token, - IFileSystem fileSystem, UriString url, - NPath targetDirectory = null, - string filename = null, - int retryCount = 0) - : base(token, fileSystem, url, targetDirectory, filename, retryCount: retryCount) - { - Name = nameof(DownloadTextTask); - } - - protected override string RunWithReturn(bool success) - { - var result = BaseRunWithReturn(success); - - RaiseOnStart(); - - try - { - result = RunDownload(success); - result = fileSystem.ReadAllText(result, Encoding.UTF8); - } - catch (Exception ex) - { - Errors = ex.Message; - if (!RaiseFaultHandlers(ex)) - throw; - } - finally - { - RaiseOnEnd(result); - } - - return result; - } - } } diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index 21b3e4abd..a4a96c45d 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -43,7 +43,7 @@ public interface ITask : IAsyncResult CancellationToken Token { get; } TaskBase DependsOn { get; } event Action OnStart; - event Action OnEnd; + event Action OnEnd; ITask GetTopOfChain(); /// @@ -74,7 +74,7 @@ public interface ITask : ITask TResult Result { get; } new Task Task { get; } new event Action> OnStart; - new event Action, TResult> OnEnd; + new event Action, TResult, bool, Exception> OnEnd; } interface ITask : ITask @@ -89,12 +89,13 @@ public abstract class TaskBase : ITask protected const TaskContinuationOptions runOnFaultOptions = TaskContinuationOptions.OnlyOnFaulted; public event Action OnStart; - public event Action OnEnd; + public event Action OnEnd; protected bool previousSuccess = true; protected Exception previousException; protected bool taskFailed = false; protected bool exceptionWasHandled = false; + protected Exception exception; protected TaskBase continuationOnSuccess; protected TaskBase continuationOnFailure; @@ -394,7 +395,7 @@ protected virtual void RaiseOnStart() protected virtual void RaiseOnEnd() { - OnEnd?.Invoke(this); + OnEnd?.Invoke(this, !taskFailed, exception); if (!taskFailed || exceptionWasHandled) { if (continuationOnSuccess == null && continuationOnAlways == null) @@ -420,6 +421,7 @@ protected void CallFinallyHandler() protected virtual bool RaiseFaultHandlers(Exception ex) { taskFailed = true; + exception = ex; if (catchHandler == null) return continuationOnFailure != null; foreach (var handler in catchHandler.GetInvocationList()) @@ -479,7 +481,8 @@ abstract class TaskBase : TaskBase, ITask private event Action finallyHandler; public new event Action> OnStart; - public new event Action, TResult> OnEnd; + public new event Action, TResult, bool, Exception> OnEnd; + private TResult result; protected TaskBase(CancellationToken token) : base(token) @@ -613,7 +616,7 @@ public ITask Finally(Action continuation, TaskAffinity protected virtual TResult RunWithReturn(bool success) { base.Run(success); - return default(TResult); + return result; } protected override void RaiseOnStart() @@ -623,9 +626,10 @@ protected override void RaiseOnStart() base.RaiseOnStart(); } - protected virtual void RaiseOnEnd(TResult result) + protected virtual void RaiseOnEnd(TResult data) { - OnEnd?.Invoke(this, result); + this.result = data; + OnEnd?.Invoke(this, result, !taskFailed, exception); if (continuationOnSuccess == null && continuationOnFailure == null && continuationOnAlways == null) { finallyHandler?.Invoke(Task.Status == TaskStatus.RanToCompletion, result); diff --git a/src/GitHub.Api/Tasks/TaskManager.cs b/src/GitHub.Api/Tasks/TaskManager.cs index bd884c8a5..dcd1322f6 100644 --- a/src/GitHub.Api/Tasks/TaskManager.cs +++ b/src/GitHub.Api/Tasks/TaskManager.cs @@ -12,7 +12,7 @@ class TaskManager : ITaskManager private CancellationTokenSource cts; private readonly ConcurrentExclusiveInterleave manager; public TaskScheduler UIScheduler { get; set; } - public TaskScheduler ConcurrentScheduler { get { return manager.ConcurrentTaskScheduler; } } + public TaskScheduler ConcurrentScheduler { get { return (TaskScheduler)manager.ConcurrentTaskScheduler; } } public TaskScheduler ExclusiveScheduler { get { return manager.ExclusiveTaskScheduler; } } public CancellationToken Token { get { return cts.Token; } } @@ -149,7 +149,7 @@ private T ScheduleConcurrent(T task, bool setupFaultHandler) TaskContinuationOptions.OnlyOnFaulted, ConcurrentScheduler ); } - return (T)task.Start(manager.ConcurrentTaskScheduler); + return (T)task.Start((TaskScheduler)manager.ConcurrentTaskScheduler); } private void Stop() diff --git a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs index c4745495a..c25325eb6 100644 --- a/src/tests/IntegrationTests/Download/DownloadTaskTests.cs +++ b/src/tests/IntegrationTests/Download/DownloadTaskTests.cs @@ -8,13 +8,14 @@ using System.Diagnostics; using GitHub.Logging; using System.Runtime.CompilerServices; +using System.Collections.Generic; namespace IntegrationTests.Download { - [TestFixture] - class DownloadTaskTests : BaseTaskManagerTest + class BaseDownloaderTest : BaseTaskManagerTest { - const int Timeout = 30000; + protected const int Timeout = 30000; + protected TestWebServer.HttpServer server; public override void OnSetup() { @@ -22,13 +23,12 @@ public override void OnSetup() InitializeEnvironment(TestBasePath, initializeRepository: false); } - private TestWebServer.HttpServer server; public override void TestFixtureSetUp() { base.TestFixtureSetUp(); server = new TestWebServer.HttpServer(SolutionDirectory.Combine("files")); Task.Factory.StartNew(server.Start); - ApplicationConfiguration.WebTimeout = 5000; + ApplicationConfiguration.WebTimeout = 50000; } public override void TestFixtureTearDown() @@ -38,14 +38,14 @@ public override void TestFixtureTearDown() ApplicationConfiguration.WebTimeout = ApplicationConfiguration.DefaultWebTimeout; } - private void StartTest(out Stopwatch watch, out ILogging logger, [CallerMemberName] string testName = "test") + protected void StartTest(out Stopwatch watch, out ILogging logger, [CallerMemberName] string testName = "test") { watch = new Stopwatch(); logger = LogHelper.GetLogger(testName); logger.Trace("Starting test"); } - private void StartTrackTime(Stopwatch watch, ILogging logger = null, string message = "") + protected void StartTrackTime(Stopwatch watch, ILogging logger = null, string message = "") { if (!String.IsNullOrEmpty(message)) logger.Trace(message); @@ -53,14 +53,198 @@ private void StartTrackTime(Stopwatch watch, ILogging logger = null, string mess watch.Start(); } - private void StopTrackTimeAndLog(Stopwatch watch, ILogging logger) + protected void StopTrackTimeAndLog(Stopwatch watch, ILogging logger) { watch.Stop(); logger.Trace($"Time: {watch.ElapsedMilliseconds}"); } + } + + [TestFixture] + class DownloaderTests : BaseDownloaderTest + { + [Test] + public async Task DownloadAndVerificationWorks() + { + Stopwatch watch; + ILogging logger; + StartTest(out watch, out logger); + + var fileSystem = Environment.FileSystem; + var fileUrl = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); + var md5Url = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); + + var downloader = new Downloader(); + StartTrackTime(watch, logger, md5Url); + downloader.QueueDownload(fileUrl, md5Url, TestBasePath); + + var task = await TaskEx.WhenAny(downloader.Start().Task, TaskEx.Delay(Timeout)); + StopTrackTimeAndLog(watch, logger); + Assert.AreEqual(downloader.Task, task); + Assert.IsTrue(downloader.Successful); + var result = await downloader.Task; + Assert.AreEqual(1, result.Count); + Assert.AreEqual(TestBasePath.Combine(fileUrl.Filename), result[0].File); + } + + [Test] + public async Task DownloadingNonExistingFileThrows() + { + Stopwatch watch; + ILogging logger; + StartTest(out watch, out logger); + + var fileSystem = Environment.FileSystem; + var fileUrl = new UriString($"http://localhost:{server.Port}/nope"); + var md5Url = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); + + var downloader = new Downloader(); + StartTrackTime(watch, logger, md5Url); + downloader.QueueDownload(fileUrl, md5Url, TestBasePath); + var task = await TaskEx.WhenAny(downloader.Start().Task, TaskEx.Delay(Timeout)); + StopTrackTimeAndLog(watch, logger); + Assert.AreEqual(downloader.Task, task); + Assert.Throws(typeof(DownloadException), async () => await downloader.Task); + } + + [Test] + public async Task FailsIfVerificationFails() + { + Stopwatch watch; + ILogging logger; + StartTest(out watch, out logger); + + var fileSystem = Environment.FileSystem; + var fileUrl = new UriString($"http://localhost:{server.Port}/git.zip"); + var md5Url = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); + + var downloader = new Downloader(); + StartTrackTime(watch, logger, md5Url); + downloader.QueueDownload(fileUrl, md5Url, TestBasePath); + var task = await TaskEx.WhenAny(downloader.Start().Task, TaskEx.Delay(Timeout)); + StopTrackTimeAndLog(watch, logger); + Assert.AreEqual(downloader.Task, task); + Assert.Throws(typeof(DownloadException), async () => await downloader.Task); + } + + [Test] + public async Task ResumingWorks() + { + Stopwatch watch; + ILogging logger; + StartTest(out watch, out logger); + + var fileSystem = Environment.FileSystem; + var fileUrl = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); + var md5Url = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); + + var downloader = new Downloader(); + StartTrackTime(watch, logger, md5Url); + downloader.QueueDownload(fileUrl, md5Url, TestBasePath); + var task = await TaskEx.WhenAny(downloader.Start().Task, TaskEx.Delay(Timeout)); + StopTrackTimeAndLog(watch, logger); + Assert.AreEqual(downloader.Task, task); + var result = await downloader.Task; + var downloadData = result.FirstOrDefault(); + + var downloadPathBytes = fileSystem.ReadAllBytes(downloadData.File); + Logger.Trace("File size {0} bytes", downloadPathBytes.Length); + + var cutDownloadPathBytes = downloadPathBytes.Take(downloadPathBytes.Length - 1000).ToArray(); + fileSystem.FileDelete(downloadData.File); + fileSystem.WriteAllBytes(downloadData + ".partial", cutDownloadPathBytes); + + downloader = new Downloader(); + StartTrackTime(watch, logger, "resuming download"); + downloader.QueueDownload(fileUrl, md5Url, TestBasePath); + task = await TaskEx.WhenAny(downloader.Start().Task, TaskEx.Delay(Timeout)); + StopTrackTimeAndLog(watch, logger); + Assert.AreEqual(downloader.Task, task); + result = await downloader.Task; + downloadData = result.FirstOrDefault(); + + var md5Sum = downloadData.File.CalculateMD5(); + var md5 = TestBasePath.Combine(md5Url.Filename).ReadAllText(); + md5Sum.Should().BeEquivalentTo(md5); + } + + [Test] + public async Task SucceedIfEverythingIsAlreadyDownloaded() + { + Stopwatch watch; + ILogging logger; + StartTest(out watch, out logger); + + var fileSystem = Environment.FileSystem; + var fileUrl = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); + var md5Url = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); + + var downloader = new Downloader(); + StartTrackTime(watch, logger, md5Url); + downloader.QueueDownload(fileUrl, md5Url, TestBasePath); + var task = await TaskEx.WhenAny(downloader.Start().Task, TaskEx.Delay(Timeout)); + StopTrackTimeAndLog(watch, logger); + Assert.AreEqual(downloader.Task, task); + var downloadData = await downloader.Task; + var downloadPath = downloadData.FirstOrDefault().File; + + downloader = new Downloader(); + StartTrackTime(watch, logger, "downloading again"); + downloader.QueueDownload(fileUrl, md5Url, TestBasePath); + task = await TaskEx.WhenAny(downloader.Start().Task, TaskEx.Delay(Timeout)); + StopTrackTimeAndLog(watch, logger); + Assert.AreEqual(downloader.Task, task); + downloadData = await downloader.Task; + downloadPath = downloadData.FirstOrDefault().File; + + var md5Sum = downloadPath.CalculateMD5(); + var md5 = TestBasePath.Combine(md5Url.Filename).ReadAllText(); + md5Sum.Should().BeEquivalentTo(md5); + } + + [Test] + public async Task DownloadsRunSideBySide() + { + Stopwatch watch; + 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.txt"); + var fileUrl2 = new UriString($"http://localhost:{server.Port}/git.zip"); + var md5Url2 = new UriString($"http://localhost:{server.Port}/git.zip.MD5.txt"); + + var events = new List(); + + var downloader = new Downloader(); + downloader.QueueDownload(fileUrl2, md5Url2, TestBasePath); + downloader.QueueDownload(fileUrl1, md5Url1, TestBasePath); + downloader.DownloadStart += d => events.Add("start " + d.Url.Filename); + downloader.DownloadComplete += d => events.Add("end " + d.Url.Filename); + downloader.DownloadFailed += (d, _) => events.Add("failed " + d.Url.Filename); + + server.Delay = 1; + StartTrackTime(watch, logger); + var task = await TaskEx.WhenAny(downloader.Start().Task, TaskEx.Delay(Timeout)); + StopTrackTimeAndLog(watch, logger); + server.Delay = 0; + + Assert.AreEqual(downloader.Task, task); + + CollectionAssert.AreEqual(new string[] { + "start git.zip", + "start git-lfs.zip", + "end git-lfs.zip", + "end git.zip", + }, events); + } + } + [TestFixture] + class DownloadTaskTests : BaseDownloaderTest + { [Test] - public void ResumingDownloadsWorks() + public async Task ResumingDownloadsWorks() { Stopwatch watch; ILogging logger; @@ -71,67 +255,47 @@ public void ResumingDownloadsWorks() var gitLfs = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); - var evtDone = new ManualResetEventSlim(false); - - string md5 = null; + var downloadTask = new DownloadTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath); StartTrackTime(watch, logger, gitLfsMd5); - new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath) - .Finally((success, r) => { - md5 = r; - evtDone.Set(); - }) - .Start(); - - evtDone.Wait(Timeout).Should().BeTrue("Finally raised the signal"); + var task = await TaskEx.WhenAny(downloadTask.Start().Task, TaskEx.Delay(Timeout)); StopTrackTimeAndLog(watch, logger); - evtDone.Reset(); + task.ShouldBeEquivalentTo(downloadTask.Task); + var downloadPath = await downloadTask.Task; + var md5 = downloadPath.ReadAllText(); Assert.NotNull(md5); - string downloadPath = null; StartTrackTime(watch, logger, gitLfs); - new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath) - .Finally((success, r) => { - downloadPath = r; - evtDone.Set(); - }) - .Start(); + downloadTask = new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath); - evtDone.Wait(Timeout).Should().BeTrue("Finally raised the signal");; + StartTrackTime(watch, logger, gitLfsMd5); + task = await TaskEx.WhenAny(downloadTask.Start().Task, TaskEx.Delay(Timeout)); StopTrackTimeAndLog(watch, logger); + task.ShouldBeEquivalentTo(downloadTask.Task); - evtDone.Reset(); - + downloadPath = await downloadTask.Task; Assert.NotNull(downloadPath); - var md5Sum = fileSystem.CalculateFileMD5(downloadPath); + var md5Sum = downloadPath.CalculateMD5(); md5Sum.Should().BeEquivalentTo(md5); - var downloadPathBytes = fileSystem.ReadAllBytes(downloadPath); + var downloadPathBytes = downloadPath.ReadAllBytes(); Logger.Trace("File size {0} bytes", downloadPathBytes.Length); var cutDownloadPathBytes = downloadPathBytes.Take(downloadPathBytes.Length - 1000).ToArray(); - fileSystem.FileDelete(downloadPath); - fileSystem.WriteAllBytes(downloadPath, cutDownloadPathBytes); + downloadPath.Delete(); + new NPath(downloadPath + ".partial").WriteAllBytes(cutDownloadPathBytes); - StartTrackTime(watch, logger, "resuming download"); - new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath) - .Finally((success, r) => { - downloadPath = r; - evtDone.Set(); - }) - .Start(); + downloadTask = new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath); - evtDone.Wait(Timeout).Should().BeTrue("Finally raised the signal");; + StartTrackTime(watch, logger, gitLfs); + task = await TaskEx.WhenAny(downloadTask.Start().Task, TaskEx.Delay(Timeout)); StopTrackTimeAndLog(watch, logger); + task.ShouldBeEquivalentTo(downloadTask.Task); + downloadPath = await downloadTask.Task; - evtDone.Reset(); - - var downloadHalfPathBytes = fileSystem.ReadAllBytes(downloadPath); - Logger.Trace("File size {0} Bytes", downloadHalfPathBytes.Length); - - md5Sum = fileSystem.CalculateFileMD5(downloadPath); + md5Sum = downloadPath.CalculateMD5(); md5Sum.Should().BeEquivalentTo(md5); } @@ -169,35 +333,35 @@ public void DownloadingNonExistingFileThrows() exceptionThrown.Should().NotBeNull(); } - [Test] - public void DownloadingATextFileWorks() - { - Stopwatch watch; - ILogging logger; - StartTest(out watch, out logger); + //[Test] + //public void DownloadingATextFileWorks() + //{ + // Stopwatch watch; + // ILogging logger; + // StartTest(out watch, out logger); - var fileSystem = Environment.FileSystem; + // var fileSystem = Environment.FileSystem; - var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); + // var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); - var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath); + // var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath); - var autoResetEvent = new AutoResetEvent(false); - string result = null; + // var autoResetEvent = new AutoResetEvent(false); + // string result = null; - StartTrackTime(watch); - downloadTask - .Finally((success, r) => { - result = r; - autoResetEvent.Set(); - }) - .Start(); + // StartTrackTime(watch); + // downloadTask + // .Finally((success, r) => { + // result = r; + // autoResetEvent.Set(); + // }) + // .Start(); - autoResetEvent.WaitOne(Timeout).Should().BeTrue("Finally raised the signal");; - StopTrackTimeAndLog(watch, logger); + // autoResetEvent.WaitOne(Timeout).Should().BeTrue("Finally raised the signal");; + // StopTrackTimeAndLog(watch, logger); - result.Should().Be("105DF1302560C5F6AA64D1930284C126"); - } + // result.Should().Be("105DF1302560C5F6AA64D1930284C126"); + //} [Test] public void DownloadingFromNonExistingDomainThrows() @@ -208,7 +372,7 @@ public void DownloadingFromNonExistingDomainThrows() var fileSystem = Environment.FileSystem; - var downloadTask = new DownloadTextTask(TaskManager.Token, fileSystem, "http://ggggithub.com/robots.txt"); + var downloadTask = new DownloadTask(TaskManager.Token, fileSystem, "http://ggggithub.com/robots.txt"); var exceptionThrown = false; var autoResetEvent = new AutoResetEvent(false); @@ -227,46 +391,42 @@ public void DownloadingFromNonExistingDomainThrows() exceptionThrown.Should().BeTrue(); } - [Test] - public void DownloadingAFileWithHashValidationWorks() - { - Stopwatch watch; - ILogging logger; - StartTest(out watch, out logger); - - var fileSystem = Environment.FileSystem; - - var gitLfs = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); - var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); - - var downloadGitLfsMd5Task = new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath); - var downloadGitLfsTask = new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath); - - var result = true; - Exception exception = null; - - var autoResetEvent = new AutoResetEvent(false); - - StartTrackTime(watch); - downloadGitLfsMd5Task - .Then((b, s) => - { - downloadGitLfsTask.ValidationHash = s; - }) - .Then(downloadGitLfsTask) - .Finally((b, ex) => { - result = b; - exception = ex; - autoResetEvent.Set(); - }) - .Start(); - - autoResetEvent.WaitOne(Timeout).Should().BeTrue("Finally raised the signal");; - StopTrackTimeAndLog(watch, logger); - - result.Should().BeTrue(); - exception.Should().BeNull(); - } + //[Test] + //public void DownloadingAFileWithHashValidationWorks() + //{ + // Stopwatch watch; + // ILogging logger; + // StartTest(out watch, out logger); + + // var fileSystem = Environment.FileSystem; + + // var gitLfs = new UriString($"http://localhost:{server.Port}/git-lfs.zip"); + // var gitLfsMd5 = new UriString($"http://localhost:{server.Port}/git-lfs.zip.MD5.txt"); + + // var downloadGitLfsMd5Task = new DownloadTextTask(TaskManager.Token, fileSystem, gitLfsMd5, TestBasePath); + // var downloadGitLfsTask = new DownloadTask(TaskManager.Token, fileSystem, gitLfs, TestBasePath); + + // var result = true; + // Exception exception = null; + + // var autoResetEvent = new AutoResetEvent(false); + + // StartTrackTime(watch); + // downloadGitLfsMd5Task + // .Then(downloadGitLfsTask) + // .Finally((b, ex) => { + // result = b; + // exception = ex; + // autoResetEvent.Set(); + // }) + // .Start(); + + // autoResetEvent.WaitOne(Timeout).Should().BeTrue("Finally raised the signal");; + // StopTrackTimeAndLog(watch, logger); + + // result.Should().BeTrue(); + // exception.Should().BeNull(); + //} [Test] public void ShutdownTimeWhenTaskManagerDisposed() diff --git a/src/tests/IntegrationTests/UnzipTaskTests.cs b/src/tests/IntegrationTests/UnzipTaskTests.cs index 07a71afc5..afffeb183 100644 --- a/src/tests/IntegrationTests/UnzipTaskTests.cs +++ b/src/tests/IntegrationTests/UnzipTaskTests.cs @@ -14,64 +14,44 @@ namespace IntegrationTests class UnzipTaskTests : BaseTaskManagerTest { [Test] - public void TaskSucceeds() + public async Task UnzipWorks() { InitializeTaskManager(); var cacheContainer = Substitute.For(); Environment = new IntegrationTestEnvironment(cacheContainer, TestBasePath, SolutionDirectory); - var destinationPath = TestBasePath.Combine("git_zip").CreateDirectory(); - var archiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", destinationPath, Environment); + var destinationPath = TestBasePath.Combine("gitlfs_zip").CreateDirectory(); + var archiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", destinationPath, Environment); - var extractedPath = TestBasePath.Combine("git_zip_extracted").CreateDirectory(); + var extractedPath = TestBasePath.Combine("gitlfs_zip_extracted").CreateDirectory(); - var zipProgress = 0; - Logger.Trace("Pct Complete {0}%", zipProgress); - var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, Environment.FileSystem, GitInstallDetails.GitExtractedMD5, - new Progress(zipFileProgress => { - var zipFileProgressInteger = (int) (zipFileProgress * 100); - if (zipProgress != zipFileProgressInteger) - { - zipProgress = zipFileProgressInteger; - Logger.Trace("Pct Complete {0}%", zipProgress); - } - })); + var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, + Environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5); - unzipTask.Start().Wait(); + await unzipTask.StartAwait(); extractedPath.DirectoryExists().Should().BeTrue(); } [Test] - public void TaskFailsWhenMD5Incorect() + public void FailsWhenMD5Incorrect() { InitializeTaskManager(); var cacheContainer = Substitute.For(); Environment = new IntegrationTestEnvironment(cacheContainer, TestBasePath, SolutionDirectory); - var destinationPath = TestBasePath.Combine("git_zip").CreateDirectory(); - var archiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", destinationPath, Environment); + var destinationPath = TestBasePath.Combine("gitlfs_zip").CreateDirectory(); + var archiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", destinationPath, Environment); - var extractedPath = TestBasePath.Combine("git_zip_extracted").CreateDirectory(); + var extractedPath = TestBasePath.Combine("gitlfs_zip_extracted").CreateDirectory(); + var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, Environment.FileSystem, "AABBCCDD"); - var failed = false; - Exception exception = null; - - var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, Environment.FileSystem, "AABBCCDD") - .Finally((b, ex) => { - failed = true; - exception = ex; - }); - - unzipTask.Start().Wait(); + Assert.Throws(async () => await unzipTask.StartAwait()); extractedPath.DirectoryExists().Should().BeFalse(); - failed.Should().BeTrue(); - exception.Should().NotBeNull(); - exception.Should().BeOfType(); } } } \ No newline at end of file diff --git a/src/tests/TaskSystemIntegrationTests/Tests.cs b/src/tests/TaskSystemIntegrationTests/Tests.cs index ae4b6e311..5a338c44b 100644 --- a/src/tests/TaskSystemIntegrationTests/Tests.cs +++ b/src/tests/TaskSystemIntegrationTests/Tests.cs @@ -136,7 +136,7 @@ public async Task ProcessOnStartOnEndTaskOrder() values.Add("OnStart"); }; - combinedTask.OnEnd += task => { + combinedTask.OnEnd += (task, success, ex) => { values.Add("OnEnd"); }; @@ -599,7 +599,7 @@ public async Task StartAndEndAreAlwaysRaised() var runOrder = new List(); ITask task = new ActionTask(Token, _ => { throw new Exception(); }); task.OnStart += _ => runOrder.Add("start"); - task.OnEnd += _ => runOrder.Add("end"); + task.OnEnd += (_, __, ___) => runOrder.Add("end"); task = task.Finally((_, __) => {}); await task.StartAndSwallowException(); diff --git a/src/tests/TestWebServer/HttpServer.cs b/src/tests/TestWebServer/HttpServer.cs index 0cd38bb5a..18614cdec 100644 --- a/src/tests/TestWebServer/HttpServer.cs +++ b/src/tests/TestWebServer/HttpServer.cs @@ -75,7 +75,8 @@ public void Start() abort = false; Logger.Info($"Waiting for a request..."); var context = listener.GetContext(); - Process(context); + var thread = new Thread(p => Process((HttpListenerContext)p)); + thread.Start(context); } catch (Exception ex) { @@ -98,7 +99,10 @@ public void Abort() private void Process(HttpListenerContext context) { + Logger.Info($"Handling request"); + var filename = context.Request.Url.AbsolutePath; + Logger.Info($"{filename}"); filename = filename.TrimStart('/'); filename = Path.Combine(rootDirectory, filename); From 197ce5c026a43d02ae119b3320de180f84acb936 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Fri, 2 Mar 2018 19:43:36 +0000 Subject: [PATCH 0212/1008] Get essential changes from fixes/prefer-local-resources (PR #590) --- src/GitHub.Api/Installer/GitInstaller.cs | 84 ++++++++++++++---------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index c8e9e28c6..f2196c18a 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -26,13 +26,14 @@ class GitInstallDetails private readonly bool onWindows; - public GitInstallDetails(NPath pluginDataPath, bool onWindows) + public GitInstallDetails(NPath baseDataPath, bool onWindows) { this.onWindows = onWindows; - PluginDataPath = pluginDataPath; + ZipPath = baseDataPath.Combine("downloads"); + ZipPath.EnsureDirectoryExists(); - var gitInstallPath = PluginDataPath.Combine(PackageNameWithVersion); + var gitInstallPath = baseDataPath.Combine(PackageNameWithVersion); GitInstallationPath = gitInstallPath; if (onWindows) @@ -60,7 +61,7 @@ public NPath GetGitLfsExecutablePath(NPath gitInstallRoot) : gitInstallRoot.Combine("libexec", "git-core", GitLfsExecutable); } - public NPath PluginDataPath { get; } + public NPath ZipPath { get; } public NPath GitInstallationPath { get; } public string GitExecutable { get; } public NPath GitExecutablePath { get; } @@ -91,9 +92,8 @@ public GitInstaller(IEnvironment environment, CancellationToken cancellationToke public GitInstaller(IEnvironment environment, CancellationToken cancellationToken, GitInstallDetails installDetails, NPath gitArchiveFilePath, NPath gitLfsArchivePath) - : this( - environment, ZipHelper.Instance, cancellationToken, installDetails, gitArchiveFilePath, - gitLfsArchivePath) + : this(environment, ZipHelper.Instance, cancellationToken, installDetails, + gitArchiveFilePath, gitLfsArchivePath) {} public GitInstaller(IEnvironment environment, IZipHelper sharpZipLibHelper, CancellationToken cancellationToken, @@ -120,7 +120,10 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) var isGitExtractedTask = new FuncTask(cancellationToken, () => { if (!IsGitExtracted()) + { + GrabZipFromResources(); return null; + } Logger.Trace("SetupGitIfNeeded: Skipped"); return installDetails.GitExecutablePath; }); @@ -140,6 +143,43 @@ public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) isGitExtractedTask.Start(); } + private void GrabZipFromResources() + { + if (gitArchiveFilePath == null || !gitArchiveFilePath.FileExists()) + gitArchiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", installDetails.ZipPath, environment); + if (!gitArchiveFilePath.FileExists()) + gitArchiveFilePath = null; + + if (gitLfsArchivePath == null || !gitLfsArchivePath.FileExists()) + gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", installDetails.ZipPath, environment); + if (!gitLfsArchivePath.FileExists()) + gitLfsArchivePath = null; + } + + private ITask CreateDownloadTask() + { + gitArchiveFilePath = installDetails.ZipPath.Combine("git.zip"); + gitLfsArchivePath = installDetails.ZipPath.Combine("git-lfs.zip"); + + var downloader = new Downloader(); + downloader.QueueDownload(installDetails.GitZipUrl, installDetails.GitZipMd5Url, installDetails.ZipPath); + downloader.QueueDownload(installDetails.GitLfsZipUrl, installDetails.GitLfsZipMd5Url, installDetails.ZipPath); + return downloader; + } + + private FuncTask CreateUnzipTasks(NPath gitExtractPath, NPath gitLfsExtractPath, NPath tempZipExtractPath) + { + var unzipGitTask = new UnzipTask(cancellationToken, gitArchiveFilePath, gitExtractPath, sharpZipLibHelper, + environment.FileSystem, GitInstallDetails.GitExtractedMD5); + var unzipGitLfsTask = new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper, + environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5); + + var moveGitTask = new FuncTask(cancellationToken, () => MoveGitAndLfs(gitExtractPath, gitLfsExtractPath, tempZipExtractPath)); + return unzipGitTask + .Then(unzipGitLfsTask) + .Then(moveGitTask); + } + private FuncTask ExtractPortableGit() { var tempZipExtractPath = NPath.CreateTempDirectory("git_zip_extract_zip_paths"); @@ -157,19 +197,6 @@ private FuncTask ExtractPortableGit() return unzipTasks; } - private FuncTask CreateUnzipTasks(NPath gitExtractPath, NPath gitLfsExtractPath, NPath tempZipExtractPath) - { - var unzipGitTask = new UnzipTask(cancellationToken, gitArchiveFilePath, gitExtractPath, sharpZipLibHelper, - environment.FileSystem, GitInstallDetails.GitExtractedMD5); - var unzipGitLfsTask = new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper, - environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5); - - var moveGitTask = new FuncTask(cancellationToken, () => MoveGitAndLfs(gitExtractPath, gitLfsExtractPath, tempZipExtractPath)); - return unzipGitTask - .Then(unzipGitLfsTask) - .Then(moveGitTask); - } - private NPath MoveGitAndLfs(NPath gitExtractPath, NPath gitLfsExtractPath, NPath tempZipExtractPath) { var targetGitLfsExecPath = installDetails.GetGitLfsExecutablePath(gitExtractPath); @@ -193,19 +220,6 @@ private NPath MoveGitAndLfs(NPath gitExtractPath, NPath gitLfsExtractPath, NPath return installDetails.GitExecutablePath; } - private ITask CreateDownloadTask() - { - gitArchiveFilePath = installDetails.PluginDataPath.Combine("git.zip"); - gitLfsArchivePath = installDetails.PluginDataPath.Combine("git-lfs.zip"); - - var downloader = new Downloader(); - - downloader.QueueDownload(installDetails.GitZipUrl, installDetails.GitZipMd5Url, installDetails.PluginDataPath); - downloader.QueueDownload(installDetails.GitLfsZipUrl, installDetails.GitLfsZipMd5Url, installDetails.PluginDataPath); - - return downloader; - } - private bool IsGitExtracted() { if (!installDetails.GitInstallationPath.DirectoryExists()) @@ -214,7 +228,7 @@ private bool IsGitExtracted() return false; } - var gitExecutableMd5 = environment.FileSystem.CalculateFileMD5(installDetails.GitExecutablePath); + var gitExecutableMd5 = installDetails.GitExecutablePath.CalculateMD5(); var expectedGitExecutableMd5 = environment.IsWindows ? GitInstallDetails.WindowsGitExecutableMD5 : GitInstallDetails.MacGitExecutableMD5; if (!expectedGitExecutableMd5.Equals(gitExecutableMd5, StringComparison.InvariantCultureIgnoreCase)) @@ -223,7 +237,7 @@ private bool IsGitExtracted() return false; } - var gitLfsExecutableMd5 = environment.FileSystem.CalculateFileMD5(installDetails.GitLfsExecutablePath); + var gitLfsExecutableMd5 = installDetails.GitLfsExecutablePath.CalculateMD5(); var expectedGitLfsExecutableMd5 = environment.IsWindows ? GitInstallDetails.WindowsGitLfsExecutableMD5 : GitInstallDetails.MacGitLfsExecutableMD5; if (!expectedGitLfsExecutableMd5.Equals(gitLfsExecutableMd5, StringComparison.InvariantCultureIgnoreCase)) From 4ee058ad28918fed38ed52188864274c5f343c79 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 11:57:02 +0100 Subject: [PATCH 0213/1008] Kill a bunch of unused code --- src/GitHub.Api/Tasks/TaskExtensions.cs | 118 ------------------ .../Editor/GitHub.Unity/UI/InitProjectView.cs | 2 +- 2 files changed, 1 insertion(+), 119 deletions(-) diff --git a/src/GitHub.Api/Tasks/TaskExtensions.cs b/src/GitHub.Api/Tasks/TaskExtensions.cs index b8a734e09..265033576 100644 --- a/src/GitHub.Api/Tasks/TaskExtensions.cs +++ b/src/GitHub.Api/Tasks/TaskExtensions.cs @@ -1,61 +1,11 @@ using GitHub.Logging; using System; -using System.Threading; using System.Threading.Tasks; namespace GitHub.Unity { static class TaskExtensions { - private static Task completedTask; - - public static Task CompletedTask - { - get - { - if (completedTask == null) - { - completedTask = TaskEx.FromResult(true); - } - return completedTask; - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "task")] - public static void Forget(this Task task) - { - } - - public static async Task SafeAwait(this Task source, Action handler = null) - { - try - { - await source; - } - catch (Exception ex) - { - LogHelper.GetLogger().Error(ex); - if (handler == null) - throw; - handler(ex); - } - } - - public static async Task SafeAwait(this Task source, Func handler = null) - { - try - { - return await source; - } - catch (Exception ex) - { - LogHelper.GetLogger().Error(ex); - if (handler == null) - throw; - return handler(ex); - } - } - public static async Task StartAwait(this ITask source, Action handler = null) { try @@ -86,41 +36,6 @@ public static async Task StartAwait(this ITask source, Func Debounce(this Action func, int milliseconds = 300) - { - var last = 0; - return arg => - { - var current = Interlocked.Increment(ref last); - TaskEx.Delay(milliseconds).ContinueWith(task => - { - if (current == last) func(arg); - task.Dispose(); - }); - }; - } - - public static Action Debounce(this Action func, int milliseconds = 300) - { - var last = 0; - return () => - { - var current = Interlocked.Increment(ref last); - TaskEx.Delay(milliseconds).ContinueWith(task => - { - if (current == last) func(); - task.Dispose(); - }); - }; - } - public static ITask Then(this ITask task, Action continuation, TaskAffinity affinity = TaskAffinity.Concurrent, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { Guard.ArgumentNotNull(continuation, "continuation"); @@ -133,13 +48,6 @@ public static ITask Then(this ITask task, Action continuation, TaskAffinit return task.Then(new ActionTask(task.Token, continuation) { Affinity = affinity, Name = "Then" }, runOptions); } - public static ITask Then(this ITask task, ActionTask nextTask, T valueForNextTask, TaskAffinity affinity = TaskAffinity.Concurrent, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) - { - Guard.ArgumentNotNull(nextTask, nameof(nextTask)); - nextTask.PreviousResult = valueForNextTask; - return task.Then(nextTask, runOptions); - } - public static ITask Then(this ITask task, Action continuation, TaskAffinity affinity = TaskAffinity.Concurrent, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { Guard.ArgumentNotNull(continuation, "continuation"); @@ -164,11 +72,6 @@ public static ITask Then(this ITask task, Task continuation, TaskAffini return task.Then(cont, runOptions); } - public static ITask Then(this ITask task, Func> continuation, TaskAffinity affinity = TaskAffinity.Concurrent, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) - { - return task.Then(continuation(), affinity, runOptions); - } - public static ITask ThenInUI(this ITask task, Action continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { return task.Then(continuation, TaskAffinity.UI, runOptions); @@ -184,11 +87,6 @@ public static ITask ThenInUI(this ITask task, Action continuation return task.Then(continuation, TaskAffinity.UI, runOptions); } - public static ITask ThenInUI(this ITask task, Func continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) - { - return task.Then(continuation, TaskAffinity.UI, runOptions); - } - public static ITask ThenInUI(this ITask task, Func continuation, TaskRunOptions runOptions = TaskRunOptions.OnSuccess) { return task.Then(continuation, TaskAffinity.UI, runOptions); @@ -200,27 +98,11 @@ public static ITask FinallyInUI(this T task, Action continua return task.Finally(continuation, TaskAffinity.UI); } - public static ITask FinallyInUI(this T task, Action continuation) - where T : ITask - { - return task.Finally((s, e) => continuation(), TaskAffinity.UI); - } - public static ITask FinallyInUI(this ITask task, Action continuation) { return task.Finally(continuation, TaskAffinity.UI); } - public static ITask FinallyInUI(this ITask task, Func continuation) - { - return task.Finally((s, e, r) => continuation(), TaskAffinity.UI); - } - - public static ITask FinallyInUI(this ITask task, Func continuation) - { - return task.Finally(continuation, TaskAffinity.UI); - } - public static Task StartAsAsync(this ITask task) { var tcs = new TaskCompletionSource(); diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs index dc889436f..37daba7cc 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/InitProjectView.cs @@ -68,7 +68,7 @@ public override void OnGUI() { isBusy = true; Manager.InitializeRepository() - .FinallyInUI(() => isBusy = false) + .FinallyInUI((s, e) => isBusy = false) .Start(); } } From b465fc6db973314b82ca4a32ce12e2e92bbf82d0 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 12:05:32 +0100 Subject: [PATCH 0214/1008] Kill some more unused code --- src/GitHub.Api/Events/RepositoryWatcher.cs | 6 --- src/GitHub.Api/Tasks/TaskBase.cs | 43 +--------------------- 2 files changed, 2 insertions(+), 47 deletions(-) diff --git a/src/GitHub.Api/Events/RepositoryWatcher.cs b/src/GitHub.Api/Events/RepositoryWatcher.cs index 7aeb49041..fc00ff014 100644 --- a/src/GitHub.Api/Events/RepositoryWatcher.cs +++ b/src/GitHub.Api/Events/RepositoryWatcher.cs @@ -169,12 +169,6 @@ private int ProcessEvents(Event[] fileEvents) var eventDirectory = new NPath(fileEvent.Directory); var fileA = eventDirectory.Combine(fileEvent.FileA); - NPath fileB = null; - if (fileEvent.FileB != null) - { - fileB = eventDirectory.Combine(fileEvent.FileB); - } - // handling events in .git/* if (fileA.IsChildOf(paths.DotGitPath)) { diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index a4a96c45d..a86bb48f2 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -33,8 +33,6 @@ public interface ITask : IAsyncResult ITask Start(TaskScheduler scheduler); ITask Progress(Action progressHandler); - void Wait(); - bool Wait(int milliseconds); bool Successful { get; } string Errors { get; } Task Task { get; } @@ -373,16 +371,6 @@ protected TaskBase GetTopMostTask(TaskBase ret, bool onlyCreatedState) return depends.GetTopMostTask(ret, onlyCreatedState); } - public virtual void Wait() - { - Task.Wait(Token); - } - - public virtual bool Wait(int milliseconds) - { - return Task.Wait(milliseconds, Token); - } - protected virtual void Run(bool success) { } @@ -443,8 +431,8 @@ protected Exception GetThrownException() if (DependsOn.Task.Status == TaskStatus.Faulted) { - var exception = DependsOn.Task.Exception; - return exception?.InnerException ?? exception; + var ex = DependsOn.Task.Exception; + return ex?.InnerException ?? ex; } return DependsOn.GetThrownException(); } @@ -707,33 +695,6 @@ protected void RaiseOnData(TData data) } } - static class TaskBaseExtensions - { - public static T Schedule(this T task, ITaskManager taskManager) - where T : ITask - { - return taskManager.Schedule(task); - } - - public static T ScheduleUI(this T task, ITaskManager taskManager) - where T : ITask - { - return taskManager.ScheduleUI(task); - } - - public static T ScheduleExclusive(this T task, ITaskManager taskManager) - where T : ITask - { - return taskManager.ScheduleExclusive(task); - } - - public static T ScheduleConcurrent(this T task, ITaskManager taskManager) - where T : ITask - { - return taskManager.ScheduleConcurrent(task); - } - } - public enum TaskAffinity { Concurrent, From ff27758c450c01ae3e1df47a604ee1d2d8bbe736 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 12:18:17 +0100 Subject: [PATCH 0215/1008] Dedupe code --- .../Editor/GitHub.Unity/ApplicationCache.cs | 238 +++--------------- 1 file changed, 36 insertions(+), 202 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs index a2ebed40b..34cece781 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs @@ -131,6 +131,9 @@ public IEnvironment Environment abstract class ManagedCacheBase : ScriptObjectSingleton where T : ScriptableObject, IManagedCache { + [SerializeField] private string lastUpdatedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); + [SerializeField] private string lastVerifiedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); + [SerializeField] private string initializedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); [NonSerialized] private DateTimeOffset? lastUpdatedAtValue; [NonSerialized] private DateTimeOffset? lastVerifiedAtValue; [NonSerialized] private DateTimeOffset? initializedAtValue; @@ -207,15 +210,26 @@ protected void SaveData(DateTimeOffset now, bool isUpdated) } public abstract TimeSpan DataTimeout { get; } - public abstract string LastUpdatedAtString { get; protected set; } - public abstract string LastVerifiedAtString { get; protected set; } - public abstract string InitializedAtString { get; protected set; } + public string LastUpdatedAtString + { + get { return lastUpdatedAtString; } + protected set { lastUpdatedAtString = value; } + } + + public string LastVerifiedAtString + { + get { return lastVerifiedAtString; } + protected set { lastVerifiedAtString = value; } + } - public bool IsInitialized + public string InitializedAtString { - get { return ApplicationCache.Instance.FirstRunAt <= InitializedAt; } + get { return initializedAtString; } + protected set { initializedAtString = value; } } + public bool IsInitialized { get { return ApplicationCache.Instance.FirstRunAt <= InitializedAt; } } + public DateTimeOffset LastUpdatedAt { get @@ -323,14 +337,12 @@ public class ArrayContainer } [Serializable] - public class StringArrayContainer: ArrayContainer - { - } + public class StringArrayContainer : ArrayContainer + {} [Serializable] public class ConfigBranchArrayContainer : ArrayContainer - { - } + {} [Serializable] class RemoteConfigBranchDictionary : Dictionary>, ISerializationCallbackReceiver, IRemoteConfigBranchDictionary @@ -348,8 +360,8 @@ public RemoteConfigBranchDictionary(Dictionary valuePair.Key, valuePair => valuePair.Value)); } - } - + } + // save the dictionary to lists public void OnBeforeSerialize() { @@ -435,9 +447,6 @@ public ConfigRemoteDictionary(IDictionary dictionary) [Location("cache/repoinfo.yaml", LocationAttribute.Location.LibraryFolder)] sealed class RepositoryInfoCache : ManagedCacheBase, IRepositoryInfoCache { - [SerializeField] private string lastUpdatedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string lastVerifiedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string firstInitializedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); [SerializeField] private GitRemote gitRemote; [SerializeField] private GitBranch gitBranch; @@ -492,24 +501,6 @@ public GitBranch? CurentGitBranch } } - public override string LastUpdatedAtString - { - get { return lastUpdatedAtString; } - protected set { lastUpdatedAtString = value; } - } - - public override string LastVerifiedAtString - { - get { return lastVerifiedAtString; } - protected set { lastVerifiedAtString = value; } - } - - public override string InitializedAtString - { - get { return firstInitializedAtString; } - protected set { firstInitializedAtString = value; } - } - public override TimeSpan DataTimeout { get { return TimeSpan.MaxValue; } @@ -519,10 +510,6 @@ public override TimeSpan DataTimeout [Location("cache/branches.yaml", LocationAttribute.Location.LibraryFolder)] sealed class BranchCache : ManagedCacheBase, IBranchCache { - [SerializeField] private string lastUpdatedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string lastVerifiedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string initializedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private ConfigBranch gitConfigBranch; [SerializeField] private ConfigRemote gitConfigRemote; @@ -609,11 +596,6 @@ public GitBranch[] LocalBranches } } - public ILocalConfigBranchDictionary LocalConfigBranches - { - get { return localConfigBranches; } - } - public GitBranch[] RemoteBranches { get { return remoteBranches; } @@ -638,11 +620,6 @@ public GitBranch[] RemoteBranches } } - public IRemoteConfigBranchDictionary RemoteConfigBranches - { - get { return remoteConfigBranches; } - } - public GitRemote[] Remotes { get { return remotes; } @@ -667,11 +644,6 @@ public GitRemote[] Remotes } } - public IConfigRemoteDictionary ConfigRemotes - { - get { return configRemotes; } - } - public void RemoveLocalBranch(string branch) { if (LocalConfigBranches.ContainsKey(branch)) @@ -710,7 +682,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])); Logger.Trace("AddRemoteBranch {0} remote:{1} branch:{2} ", now, remote, branch); SaveData(now, true); } @@ -765,36 +737,15 @@ public void SetLocals(Dictionary branchDictionary) SaveData(now, true); } - public override string LastUpdatedAtString - { - get { return lastUpdatedAtString; } - protected set { lastUpdatedAtString = value; } - } - - public override string LastVerifiedAtString - { - get { return lastVerifiedAtString; } - protected set { lastVerifiedAtString = value; } - } - - public override string InitializedAtString - { - get { return initializedAtString; } - protected set { initializedAtString = value; } - } - - public override TimeSpan DataTimeout - { - get { return TimeSpan.MaxValue; } - } + public ILocalConfigBranchDictionary LocalConfigBranches { get { return localConfigBranches; } } + public IRemoteConfigBranchDictionary RemoteConfigBranches { get { return remoteConfigBranches; } } + public IConfigRemoteDictionary ConfigRemotes { get { return configRemotes; } } + public override TimeSpan DataTimeout { get { return TimeSpan.MaxValue; } } } [Location("cache/gitlog.yaml", LocationAttribute.Location.LibraryFolder)] sealed class GitLogCache : ManagedCacheBase, IGitLogCache { - [SerializeField] private string lastUpdatedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string lastVerifiedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string initializedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); [SerializeField] private List log = new List(); public GitLogCache() : base(true) @@ -824,36 +775,12 @@ public List Log } } - public override string LastUpdatedAtString - { - get { return lastUpdatedAtString; } - protected set { lastUpdatedAtString = value; } - } - - public override string LastVerifiedAtString - { - get { return lastVerifiedAtString; } - protected set { lastVerifiedAtString = value; } - } - - public override string InitializedAtString - { - get { return initializedAtString; } - protected set { initializedAtString = value; } - } - - public override TimeSpan DataTimeout - { - get { return TimeSpan.FromMinutes(1); } - } + public override TimeSpan DataTimeout { get { return TimeSpan.FromMinutes(1); } } } [Location("cache/gittrackingstatus.yaml", LocationAttribute.Location.LibraryFolder)] sealed class GitTrackingStatusCache : ManagedCacheBase, IGitTrackingStatusCache { - [SerializeField] private string lastUpdatedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string lastVerifiedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string initializedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); [SerializeField] private int ahead; [SerializeField] private int behind; @@ -908,36 +835,12 @@ public int Behind } } - public override string LastUpdatedAtString - { - get { return lastUpdatedAtString; } - protected set { lastUpdatedAtString = value; } - } - - public override string LastVerifiedAtString - { - get { return lastVerifiedAtString; } - protected set { lastVerifiedAtString = value; } - } - - public override string InitializedAtString - { - get { return initializedAtString; } - protected set { initializedAtString = value; } - } - - public override TimeSpan DataTimeout - { - get { return TimeSpan.FromMinutes(1); } - } + public override TimeSpan DataTimeout { get { return TimeSpan.FromMinutes(1); } } } - [Location("cache/gitstatusentries.yaml", LocationAttribute.Location.LibraryFolder)] + [Location("cache/gitstatusentries.yaml", LocationAttribute.Location.LibraryFolder)] sealed class GitStatusEntriesCache : ManagedCacheBase, IGitStatusEntriesCache { - [SerializeField] private string lastUpdatedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string lastVerifiedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string initializedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); [SerializeField] private List entries = new List(); public GitStatusEntriesCache() : base(true) @@ -967,36 +870,12 @@ public List Entries } } - public override string LastUpdatedAtString - { - get { return lastUpdatedAtString; } - protected set { lastUpdatedAtString = value; } - } - - public override string LastVerifiedAtString - { - get { return lastVerifiedAtString; } - protected set { lastVerifiedAtString = value; } - } - - public override string InitializedAtString - { - get { return initializedAtString; } - protected set { initializedAtString = value; } - } - - public override TimeSpan DataTimeout - { - get { return TimeSpan.FromMinutes(1); } - } + public override TimeSpan DataTimeout { get { return TimeSpan.FromMinutes(1); } } } [Location("cache/gitlocks.yaml", LocationAttribute.Location.LibraryFolder)] sealed class GitLocksCache : ManagedCacheBase, IGitLocksCache { - [SerializeField] private string lastUpdatedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string lastVerifiedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string initializedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); [SerializeField] private List gitLocks = new List(); public GitLocksCache() : base(true) @@ -1026,41 +905,17 @@ public List GitLocks } } - public override string LastUpdatedAtString - { - get { return lastUpdatedAtString; } - protected set { lastUpdatedAtString = value; } - } - - public override string LastVerifiedAtString - { - get { return lastVerifiedAtString; } - protected set { lastVerifiedAtString = value; } - } - - public override string InitializedAtString - { - get { return initializedAtString; } - protected set { initializedAtString = value; } - } - - public override TimeSpan DataTimeout - { - get { return TimeSpan.FromMinutes(1); } - } + public override TimeSpan DataTimeout { get { return TimeSpan.FromMinutes(1); } } } [Location("cache/gituser.yaml", LocationAttribute.Location.LibraryFolder)] sealed class GitUserCache : ManagedCacheBase, IGitUserCache { - [SerializeField] private string lastUpdatedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string lastVerifiedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); - [SerializeField] private string initializedAtString = DateTimeOffset.MinValue.ToString(Constants.Iso8601Format); [SerializeField] private string gitName; [SerializeField] private string gitEmail; public GitUserCache() : base(true) - { } + {} public string Name { @@ -1110,27 +965,6 @@ public string Email } } - public override string LastUpdatedAtString - { - get { return lastUpdatedAtString; } - protected set { lastUpdatedAtString = value; } - } - - public override string LastVerifiedAtString - { - get { return lastVerifiedAtString; } - protected set { lastVerifiedAtString = value; } - } - - public override string InitializedAtString - { - get { return initializedAtString; } - protected set { initializedAtString = value; } - } - - public override TimeSpan DataTimeout - { - get { return TimeSpan.FromMinutes(10); } - } + public override TimeSpan DataTimeout { get { return TimeSpan.FromMinutes(10); } } } } From fbff0719a86c7bfff7d1b0419fdef43259f2ef15 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 12:26:19 +0100 Subject: [PATCH 0216/1008] Fix typo --- src/GitHub.Api/Cache/CacheInterfaces.cs | 4 ++-- src/GitHub.Api/Git/Repository.cs | 8 ++++---- .../Assets/Editor/GitHub.Unity/ApplicationCache.cs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/GitHub.Api/Cache/CacheInterfaces.cs b/src/GitHub.Api/Cache/CacheInterfaces.cs index fd205f46d..414a71384 100644 --- a/src/GitHub.Api/Cache/CacheInterfaces.cs +++ b/src/GitHub.Api/Cache/CacheInterfaces.cs @@ -84,7 +84,7 @@ public interface IConfigRemoteDictionary : IDictionary public interface IBranchCache : IManagedCache { ConfigRemote? CurrentConfigRemote { get; set; } - ConfigBranch? CurentConfigBranch { get; set; } + ConfigBranch? CurrentConfigBranch { get; set; } GitBranch[] LocalBranches { get; set; } GitBranch[] RemoteBranches { get; set; } @@ -105,7 +105,7 @@ public interface IBranchCache : IManagedCache public interface IRepositoryInfoCache : IManagedCache { GitRemote? CurrentGitRemote { get; set; } - GitBranch? CurentGitBranch { get; set; } + GitBranch? CurrentGitBranch { get; set; } } public interface IGitLogCache : IManagedCache diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 16e509c05..231c727cb 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -523,8 +523,8 @@ public GitBranch[] RemoteBranches private ConfigBranch? CurrentConfigBranch { - get { return this.cacheContainer.BranchCache.CurentConfigBranch; } - set { cacheContainer.BranchCache.CurentConfigBranch = value; } + get { return this.cacheContainer.BranchCache.CurrentConfigBranch; } + set { cacheContainer.BranchCache.CurrentConfigBranch = value; } } private ConfigRemote? CurrentConfigRemote @@ -553,8 +553,8 @@ public List CurrentChanges public GitBranch? CurrentBranch { - get { return cacheContainer.RepositoryInfoCache.CurentGitBranch; } - private set { cacheContainer.RepositoryInfoCache.CurentGitBranch = value; } + get { return cacheContainer.RepositoryInfoCache.CurrentGitBranch; } + private set { cacheContainer.RepositoryInfoCache.CurrentGitBranch = value; } } public string CurrentBranchName => CurrentConfigBranch?.Name; diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs index 34cece781..bb18ac9df 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs @@ -477,7 +477,7 @@ public GitRemote? CurrentGitRemote } } - public GitBranch? CurentGitBranch + public GitBranch? CurrentGitBranch { get { @@ -548,7 +548,7 @@ public ConfigRemote? CurrentConfigRemote } } - public ConfigBranch? CurentConfigBranch + public ConfigBranch? CurrentConfigBranch { get { From 24be3ee987c86aef9ff854deb57b833cc1cdbe5e Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 12:33:41 +0100 Subject: [PATCH 0217/1008] DataTimeout should never be infinite, otherwise invalid data will never be fixed --- .../Assets/Editor/GitHub.Unity/ApplicationCache.cs | 7 ++----- .../Assets/Editor/GitHub.Unity/CacheContainer.cs | 2 ++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs index bb18ac9df..b65802528 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs @@ -501,10 +501,7 @@ public GitBranch? CurrentGitBranch } } - public override TimeSpan DataTimeout - { - get { return TimeSpan.MaxValue; } - } + public override TimeSpan DataTimeout { get { return TimeSpan.FromDays(1); } } } [Location("cache/branches.yaml", LocationAttribute.Location.LibraryFolder)] @@ -740,7 +737,7 @@ public void SetLocals(Dictionary branchDictionary) public ILocalConfigBranchDictionary LocalConfigBranches { get { return localConfigBranches; } } public IRemoteConfigBranchDictionary RemoteConfigBranches { get { return remoteConfigBranches; } } public IConfigRemoteDictionary ConfigRemotes { get { return configRemotes; } } - public override TimeSpan DataTimeout { get { return TimeSpan.MaxValue; } } + public override TimeSpan DataTimeout { get { return TimeSpan.FromDays(1); } } } [Location("cache/gitlog.yaml", LocationAttribute.Location.LibraryFolder)] diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/CacheContainer.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/CacheContainer.cs index e97090963..584a1c012 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/CacheContainer.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/CacheContainer.cs @@ -59,6 +59,7 @@ public void Validate(CacheType cacheType) public void ValidateAll() { + RepositoryInfoCache.ValidateData(); BranchCache.ValidateData(); GitLogCache.ValidateData(); GitTrackingStatusCache.ValidateData(); @@ -73,6 +74,7 @@ public void Invalidate(CacheType cacheType) public void InvalidateAll() { + RepositoryInfoCache.InvalidateData(); BranchCache.InvalidateData(); GitLogCache.InvalidateData(); GitTrackingStatusCache.InvalidateData(); From f2ee4ef04b4282109b2f0eca32e4cbf422d6a096 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 13:45:38 +0100 Subject: [PATCH 0218/1008] Fix initialization sequence and cache invalidation on startup --- .../Application/ApplicationManagerBase.cs | 44 ++++++++++--------- src/GitHub.Api/Git/Repository.cs | 1 + src/GitHub.Api/Git/RepositoryManager.cs | 5 ++- src/GitHub.Api/Installer/GitInstaller.cs | 17 ++----- .../Editor/GitHub.Unity/ApplicationCache.cs | 9 ++-- 5 files changed, 33 insertions(+), 43 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 535614595..542e54c16 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -47,7 +47,7 @@ public void Run(bool firstRun) { Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory); - var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath(); + var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath(); if (gitExecutablePath != null && gitExecutablePath.FileExists()) // we have a git path { Logger.Trace("Using git install path from settings: {0}", gitExecutablePath); @@ -57,7 +57,10 @@ public void Run(bool firstRun) { Logger.Trace("No git path found in settings"); - var initEnvironmentTask = new ActionTask(CancellationToken, (b, path) => InitializeEnvironment(path)) { Affinity = TaskAffinity.UI }; + var initEnvironmentTask = new ActionTask(CancellationToken, (b, path) => + { + InitializeEnvironment(path); + }) { Affinity = TaskAffinity.UI }; var findExecTask = new FindExecTask("git", CancellationToken) .FinallyInUI((b, ex, path) => { if (b && path != null) @@ -72,8 +75,7 @@ public void Run(bool firstRun) } }); - var installDetails = new GitInstallDetails(Environment.UserCachePath, true); - var gitInstaller = new GitInstaller(Environment, CancellationToken, installDetails); + var gitInstaller = new GitInstaller(Environment, CancellationToken); // if successful, continue with environment initialization, otherwise try to find an existing git installation gitInstaller.SetupGitIfNeeded(initEnvironmentTask, findExecTask); @@ -171,34 +173,34 @@ protected void SetupMetrics(string unityVersion, bool firstRun) /// private void InitializeEnvironment(NPath gitExecutablePath) { - var afterGitSetup = new ActionTask(CancellationToken, RestartRepository) - .ThenInUI(InitializeUI); - Environment.GitExecutablePath = gitExecutablePath; Environment.User.Initialize(GitClient); + var afterGitSetup = new ActionTask(CancellationToken, RestartRepository) + .ThenInUI(InitializeUI); + + ITask task = afterGitSetup; if (Environment.IsWindows) { - var task = GitClient - .GetConfig("credential.helper", GitConfigSource.Global) - .Then((b, credentialHelper) => { - if (string.IsNullOrEmpty(credentialHelper)) + 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"); - throw new ArgumentNullException(nameof(credentialHelper)); + thisTask + .Then(GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global)) + .Then(afterGitSetup); } - }); - // if there's no credential helper, set it before restarting the repository - task.Then(GitClient.SetConfig("credential.helper", "wincred", GitConfigSource.Global), TaskRunOptions.OnFailure) - .Then(afterGitSetup, taskIsTopOfChain: true); - - // if there's a credential helper, we're good, restart the repository - task.Then(afterGitSetup, TaskRunOptions.OnSuccess, taskIsTopOfChain: true); + else + thisTask.Then(afterGitSetup); + }; + task = credHelperTask; } - - afterGitSetup.Start(); + task.Start(); } + private bool disposed = false; protected virtual void Dispose(bool disposing) { diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 231c727cb..8157753d3 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -298,6 +298,7 @@ private void CacheContainer_OnCacheInvalidated(CacheType cacheType) break; case CacheType.RepositoryInfoCache: + repositoryManager?.UpdateRepositoryInfo(); break; case CacheType.GitStatusEntriesCache: diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index ca7113297..cdbb4bff7 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -46,6 +46,7 @@ public interface IRepositoryManager : IDisposable IGitConfig Config { get; } IGitClient GitClient { get; } bool IsBusy { get; } + void UpdateRepositoryInfo(); } interface IRepositoryPathConfiguration @@ -443,7 +444,7 @@ private void SetupWatcher() private void UpdateHead() { Logger.Trace("UpdateHead"); - UpdateCurrentBranchAndRemote(); + UpdateRepositoryInfo(); UpdateGitLog(); } @@ -452,7 +453,7 @@ private string GetCurrentHead() return repositoryPaths.DotGitHead.ReadAllLines().FirstOrDefault(); } - private void UpdateCurrentBranchAndRemote() + public void UpdateRepositoryInfo() { ConfigBranch? branch; ConfigRemote? remote; diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index f2196c18a..574530f78 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -86,23 +86,12 @@ class GitInstaller private NPath gitLfsArchivePath; public GitInstaller(IEnvironment environment, CancellationToken cancellationToken, - GitInstallDetails installDetails) - : this(environment, ZipHelper.Instance, cancellationToken, installDetails, null, null) - {} - - public GitInstaller(IEnvironment environment, CancellationToken cancellationToken, - GitInstallDetails installDetails, NPath gitArchiveFilePath, NPath gitLfsArchivePath) - : this(environment, ZipHelper.Instance, cancellationToken, installDetails, - gitArchiveFilePath, gitLfsArchivePath) - {} - - public GitInstaller(IEnvironment environment, IZipHelper sharpZipLibHelper, CancellationToken cancellationToken, - GitInstallDetails installDetails, NPath gitArchiveFilePath, NPath gitLfsArchivePath) + GitInstallDetails installDetails = null, NPath gitArchiveFilePath = null, NPath gitLfsArchivePath = null) { this.environment = environment; - this.sharpZipLibHelper = sharpZipLibHelper; + this.sharpZipLibHelper = ZipHelper.Instance; this.cancellationToken = cancellationToken; - this.installDetails = installDetails; + this.installDetails = installDetails ?? new GitInstallDetails(environment.UserCachePath, environment.IsWindows); this.gitArchiveFilePath = gitArchiveFilePath; this.gitLfsArchivePath = gitLfsArchivePath; } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs index b65802528..cd5be9dea 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/ApplicationCache.cs @@ -151,13 +151,10 @@ protected ManagedCacheBase(bool invalidOnFirstRun) public void ValidateData() { var initialized = ValidateInitialized(); - if (initialized) + if (!initialized || DateTimeOffset.Now - LastUpdatedAt > DataTimeout) { - if (DateTimeOffset.Now - LastUpdatedAt > DataTimeout) - { - Logger.Trace("Timeout Invalidation"); - InvalidateData(); - } + Logger.Trace("Timeout Invalidation"); + InvalidateData(); } } From 883ed16caeb7fa9eea31847f5060abc143c9d870 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 13:47:59 +0100 Subject: [PATCH 0219/1008] GitInstallDetails is better off under GitInstaller --- src/GitHub.Api/Installer/GitInstaller.cs | 138 +++++++++--------- .../BasePlatformIntegrationTest.cs | 2 +- .../Installer/GitInstallerTests.cs | 10 +- src/tests/IntegrationTests/UnzipTaskTests.cs | 2 +- 4 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index 574530f78..edd9f61cd 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -5,75 +5,6 @@ namespace GitHub.Unity { - class GitInstallDetails - { - public const string DefaultGitZipMd5Url = "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt"; - 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.txt"; - public const string DefaultGitLfsZipUrl = "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip"; - - public const string GitExtractedMD5 = "e6cfc0c294a2312042f27f893dfc9c0a"; - public const string GitLfsExtractedMD5 = "36e3ae968b69fbf42dff72311040d24a"; - - public const string WindowsGitExecutableMD5 = "50570ed932559f294d1a1361801740b9"; - public const string MacGitExecutableMD5 = ""; - - public const string WindowsGitLfsExecutableMD5 = "177bb14d0c08f665a24f0d5516c3b080"; - public const string MacGitLfsExecutableMD5 = "f81a1a065a26a4123193e8fd96c561ad"; - - private const string PackageVersion = "f02737a78695063deace08e96d5042710d3e32db"; - private const string PackageName = "PortableGit"; - - private readonly bool onWindows; - - public GitInstallDetails(NPath baseDataPath, bool onWindows) - { - this.onWindows = onWindows; - - ZipPath = baseDataPath.Combine("downloads"); - ZipPath.EnsureDirectoryExists(); - - var gitInstallPath = baseDataPath.Combine(PackageNameWithVersion); - GitInstallationPath = gitInstallPath; - - if (onWindows) - { - GitExecutable += "git.exe"; - GitLfsExecutable += "git-lfs.exe"; - - GitExecutablePath = gitInstallPath.Combine("cmd", GitExecutable); - } - else - { - GitExecutable = "git"; - GitLfsExecutable = "git-lfs"; - - GitExecutablePath = gitInstallPath.Combine("bin", GitExecutable); - } - - GitLfsExecutablePath = GetGitLfsExecutablePath(gitInstallPath); - } - - public NPath GetGitLfsExecutablePath(NPath gitInstallRoot) - { - return onWindows - ? gitInstallRoot.Combine("mingw32", "libexec", "git-core", GitLfsExecutable) - : gitInstallRoot.Combine("libexec", "git-core", GitLfsExecutable); - } - - public NPath ZipPath { get; } - public NPath GitInstallationPath { get; } - public string GitExecutable { get; } - public NPath GitExecutablePath { get; } - public string GitLfsExecutable { get; } - public NPath GitLfsExecutablePath { get; } - public UriString GitZipMd5Url { get; set; } = DefaultGitZipMd5Url; - public UriString GitZipUrl { get; set; } = DefaultGitZipUrl; - public UriString GitLfsZipMd5Url { get; set; } = DefaultGitLfsZipMd5Url; - public UriString GitLfsZipUrl { get; set; } = DefaultGitLfsZipUrl; - public string PackageNameWithVersion => PackageName + "_" + PackageVersion; - } - class GitInstaller { private static readonly ILogging Logger = LogHelper.GetLogger(); @@ -238,5 +169,74 @@ private bool IsGitExtracted() Logger.Trace("Git Present"); return true; } + + public class GitInstallDetails + { + public const string DefaultGitZipMd5Url = "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt"; + 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.txt"; + public const string DefaultGitLfsZipUrl = "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip"; + + public const string GitExtractedMD5 = "e6cfc0c294a2312042f27f893dfc9c0a"; + public const string GitLfsExtractedMD5 = "36e3ae968b69fbf42dff72311040d24a"; + + public const string WindowsGitExecutableMD5 = "50570ed932559f294d1a1361801740b9"; + public const string MacGitExecutableMD5 = ""; + + public const string WindowsGitLfsExecutableMD5 = "177bb14d0c08f665a24f0d5516c3b080"; + public const string MacGitLfsExecutableMD5 = "f81a1a065a26a4123193e8fd96c561ad"; + + private const string PackageVersion = "f02737a78695063deace08e96d5042710d3e32db"; + private const string PackageName = "PortableGit"; + + private readonly bool onWindows; + + public GitInstallDetails(NPath baseDataPath, bool onWindows) + { + this.onWindows = onWindows; + + ZipPath = baseDataPath.Combine("downloads"); + ZipPath.EnsureDirectoryExists(); + + var gitInstallPath = baseDataPath.Combine(PackageNameWithVersion); + GitInstallationPath = gitInstallPath; + + if (onWindows) + { + GitExecutable += "git.exe"; + GitLfsExecutable += "git-lfs.exe"; + + GitExecutablePath = gitInstallPath.Combine("cmd", GitExecutable); + } + else + { + GitExecutable = "git"; + GitLfsExecutable = "git-lfs"; + + GitExecutablePath = gitInstallPath.Combine("bin", GitExecutable); + } + + GitLfsExecutablePath = GetGitLfsExecutablePath(gitInstallPath); + } + + public NPath GetGitLfsExecutablePath(NPath gitInstallRoot) + { + return onWindows + ? gitInstallRoot.Combine("mingw32", "libexec", "git-core", GitLfsExecutable) + : gitInstallRoot.Combine("libexec", "git-core", GitLfsExecutable); + } + + public NPath ZipPath { get; } + public NPath GitInstallationPath { get; } + public string GitExecutable { get; } + public NPath GitExecutablePath { get; } + public string GitLfsExecutable { get; } + public NPath GitLfsExecutablePath { get; } + public UriString GitZipMd5Url { get; set; } = DefaultGitZipMd5Url; + public UriString GitZipUrl { get; set; } = DefaultGitZipUrl; + public UriString GitLfsZipMd5Url { get; set; } = DefaultGitLfsZipMd5Url; + public UriString GitLfsZipUrl { get; set; } = DefaultGitLfsZipUrl; + public string PackageNameWithVersion => PackageName + "_" + PackageVersion; } } +} diff --git a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs index 37261448a..f943fed7b 100644 --- a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs +++ b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs @@ -30,7 +30,7 @@ protected void InitializePlatform(NPath repoPath, NPath environmentPath, bool en var autoResetEvent = new AutoResetEvent(false); var applicationDataPath = Environment.GetSpecialFolder(System.Environment.SpecialFolder.LocalApplicationData).ToNPath(); - var installDetails = new GitInstallDetails(applicationDataPath, true); + var installDetails = new GitInstaller.GitInstallDetails(applicationDataPath, true); var zipArchivesPath = TestBasePath.Combine("ZipArchives").CreateDirectory(); var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); diff --git a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs index da8824978..e13cde9a8 100644 --- a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs +++ b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs @@ -40,12 +40,12 @@ public void GitInstallTest() { var gitInstallationPath = TestBasePath.Combine("GitInstall").CreateDirectory(); - var installDetails = new GitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows) + var installDetails = new GitInstaller.GitInstallDetails(gitInstallationPath, DefaultEnvironment.OnWindows) { - GitZipMd5Url = $"http://localhost:{server.Port}/{new UriString(GitInstallDetails.DefaultGitZipMd5Url).Filename}", - GitZipUrl = $"http://localhost:{server.Port}/{new UriString(GitInstallDetails.DefaultGitZipUrl).Filename}", - GitLfsZipMd5Url = $"http://localhost:{server.Port}/{new UriString(GitInstallDetails.DefaultGitLfsZipMd5Url).Filename}", - GitLfsZipUrl = $"http://localhost:{server.Port}/{new UriString(GitInstallDetails.DefaultGitLfsZipUrl).Filename}", + GitZipMd5Url = $"http://localhost:{server.Port}/{new UriString(GitInstaller.GitInstallDetails.DefaultGitZipMd5Url).Filename}", + GitZipUrl = $"http://localhost:{server.Port}/{new UriString(GitInstaller.GitInstallDetails.DefaultGitZipUrl).Filename}", + GitLfsZipMd5Url = $"http://localhost:{server.Port}/{new UriString(GitInstaller.GitInstallDetails.DefaultGitLfsZipMd5Url).Filename}", + GitLfsZipUrl = $"http://localhost:{server.Port}/{new UriString(GitInstaller.GitInstallDetails.DefaultGitLfsZipUrl).Filename}", }; TestBasePath.Combine("git").CreateDirectory(); diff --git a/src/tests/IntegrationTests/UnzipTaskTests.cs b/src/tests/IntegrationTests/UnzipTaskTests.cs index afffeb183..634fdcf92 100644 --- a/src/tests/IntegrationTests/UnzipTaskTests.cs +++ b/src/tests/IntegrationTests/UnzipTaskTests.cs @@ -27,7 +27,7 @@ public async Task UnzipWorks() var extractedPath = TestBasePath.Combine("gitlfs_zip_extracted").CreateDirectory(); var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, - Environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5); + Environment.FileSystem, GitInstaller.GitInstallDetails.GitLfsExtractedMD5); await unzipTask.StartAwait(); From 732c52198ced735263d7453ad00d9cb244d8d661 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 5 Mar 2018 10:00:54 -0500 Subject: [PATCH 0220/1008] Getting things working manually --- octorun/src/authentication.js | 98 ++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 30 deletions(-) diff --git a/octorun/src/authentication.js b/octorun/src/authentication.js index ebaebd26e..bdf59c3d2 100644 --- a/octorun/src/authentication.js +++ b/octorun/src/authentication.js @@ -1,43 +1,81 @@ -var readlineSync = require("readline-sync"); var config = require("./configuration"); var octokitWrapper = require("./octokit"); var scopes = ["user", "repo", "gist", "write:public_key"]; +var stdIn = process.openStdin(); + +var awaiter = null; + +stdIn.addListener("data", function(d){ + var content = d.toString().trim(); + + if(awaiter) + { + var _awaiter = awaiter; + awaiter = null; + _awaiter(content); + } +}); + var handleBasicAuthentication = function (onSuccess, onRequiresTwoFa, onFailure) { - var user = readlineSync.question('User: '); - var pwd = readlineSync.question('Password: ', { - hideEchoBack: true - }); + var username = null; + var password = null; - var octokit = octokitWrapper.createOctokit(); + var withPassword = function(input) { + password = input; + } - octokit.authenticate({ - type: "basic", - username: user, - password: pwd - }); + var promptPassword = function(){ + awaiter = withPassword; + } - octokit.authorization.create({ - scopes: scopes, - note: config.appName, - client_id: config.clientId, - client_secret: config.clientSecret - }, function (err, res) { - if (err) { - if (err.message === '{"message":"Must specify two-factor authentication OTP code.","documentation_url":"https://developer.github.com/v3/auth#working-with-two-factor-authentication"}') { - onRequiresTwoFa(); - return; - } - else { - onFailure(err) - } - } - else { - onSuccess(res.data.token); - } - }); + var withUser = function(input) { + username = input; + promptPassword(); + } + + var promptUser = function() { + awaiter = withUser; + } + + promptUser(); + + + // var user = readlineSync.question('User: '); + + // var pwd = readlineSync.question('Password: ', { + // hideEchoBack: true + // }); + + // var octokit = octokitWrapper.createOctokit(); + + // octokit.authenticate({ + // type: "basic", + // username: user, + // password: pwd + // }); + + // octokit.authorization.create({ + // scopes: scopes, + // note: config.appName, + // client_id: config.clientId, + // client_secret: config.clientSecret + // }, function (err, res) { + // if (err) { + // if (err.message === '{"message":"Must specify two-factor authentication OTP code.","documentation_url":"https://developer.github.com/v3/auth#working-with-two-factor-authentication"}') { + // onRequiresTwoFa(); + // return; + // } + // else { + // onFailure(err) + // } + // } + // else { + // onSuccess(res.data.token); + // } + // }); } var handleTwoFactorAuthentication = function (onSuccess, onFailure) { From 76e34d4d89dc9e9b538695b0de3c6f90d67fe042 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 5 Mar 2018 10:26:04 -0500 Subject: [PATCH 0221/1008] Removing readline-sync --- octorun/package.json | 3 +- octorun/src/authentication.js | 172 +++++++++++++++++++--------------- 2 files changed, 97 insertions(+), 78 deletions(-) diff --git a/octorun/package.json b/octorun/package.json index dc1ceee3e..f7237151e 100644 --- a/octorun/package.json +++ b/octorun/package.json @@ -12,7 +12,6 @@ "dependencies": { "commander": "^2.14.1", "dotenv": "^1.0.0", - "octokit-rest-for-node-v0.12": "1.0.1", - "readline-sync": "^1.4.9" + "octokit-rest-for-node-v0.12": "1.0.1" } } diff --git a/octorun/src/authentication.js b/octorun/src/authentication.js index bdf59c3d2..a8cdda693 100644 --- a/octorun/src/authentication.js +++ b/octorun/src/authentication.js @@ -7,11 +7,10 @@ var stdIn = process.openStdin(); var awaiter = null; -stdIn.addListener("data", function(d){ +stdIn.addListener("data", function (d) { var content = d.toString().trim(); - - if(awaiter) - { + + if (awaiter) { var _awaiter = awaiter; awaiter = null; _awaiter(content); @@ -19,98 +18,119 @@ stdIn.addListener("data", function(d){ }); var handleBasicAuthentication = function (onSuccess, onRequiresTwoFa, onFailure) { - var username = null; var password = null; - var withPassword = function(input) { + var withPassword = function (input) { password = input; + + var octokit = octokitWrapper.createOctokit(); + + octokit.authenticate({ + type: "basic", + username: username, + password: password + }); + + octokit.authorization.create({ + scopes: scopes, + note: config.appName, + client_id: config.clientId, + client_secret: config.clientSecret + }, function (err, res) { + if (err) { + if (err.message === '{"message":"Must specify two-factor authentication OTP code.","documentation_url":"https://developer.github.com/v3/auth#working-with-two-factor-authentication"}') { + onRequiresTwoFa(); + return; + } + else { + onFailure(err) + } + } + else { + onSuccess(res.data.token); + } + }); } - var promptPassword = function(){ + var promptPassword = function () { + process.stdout.write("Password: "); awaiter = withPassword; } - var withUser = function(input) { + var withUser = function (input) { username = input; promptPassword(); } - var promptUser = function() { + var promptUser = function () { + process.stdout.write("Username: "); awaiter = withUser; } promptUser(); - - - // var user = readlineSync.question('User: '); - - // var pwd = readlineSync.question('Password: ', { - // hideEchoBack: true - // }); - - // var octokit = octokitWrapper.createOctokit(); - - // octokit.authenticate({ - // type: "basic", - // username: user, - // password: pwd - // }); - - // octokit.authorization.create({ - // scopes: scopes, - // note: config.appName, - // client_id: config.clientId, - // client_secret: config.clientSecret - // }, function (err, res) { - // if (err) { - // if (err.message === '{"message":"Must specify two-factor authentication OTP code.","documentation_url":"https://developer.github.com/v3/auth#working-with-two-factor-authentication"}') { - // onRequiresTwoFa(); - // return; - // } - // else { - // onFailure(err) - // } - // } - // else { - // onSuccess(res.data.token); - // } - // }); } var handleTwoFactorAuthentication = function (onSuccess, onFailure) { - var user = readlineSync.question('User: '); - - var pwd = readlineSync.question('Password: ', { - hideEchoBack: true - }); - - var twofa = readlineSync.question('TwoFactor: '); - - var octokit = octokitWrapper.createOctokit(); - - octokit.authenticate({ - type: "basic", - username: user, - password: pwd - }); - - octokit.authorization.create({ - scopes: scopes, - note: config.appName, - client_id: config.clientId, - client_secret: config.clientSecret, - headers: { - "X-GitHub-OTP": twofa - } - }, function (err, res) { - if (err) { - onFailure(err) - } - else { - onSuccess(res.data.token); - } - }); + var username = null; + var password = null; + var twoFactor = null; + + var withTwoFactor = function (input) { + twoFactor = input; + + var octokit = octokitWrapper.createOctokit(); + + octokit.authenticate({ + type: "basic", + username: username, + password: password + }); + + octokit.authorization.create({ + scopes: scopes, + note: config.appName, + client_id: config.clientId, + client_secret: config.clientSecret, + headers: { + "X-GitHub-OTP": twoFactor + } + }, function (err, res) { + if (err) { + onFailure(err) + } + else { + onSuccess(res.data.token); + } + }); + } + + var promptTwoFactor = function () { + process.stdout.write("Two Factor: "); + awaiter = withTwoFactor; + } + + var withPassword = function (input) { + password = input; + promptTwoFactor(); + } + + var promptPassword = function () { + process.stdout.write("Password: "); + awaiter = withPassword; + } + + var withUser = function (input) { + username = input; + promptPassword(); + } + + var promptUser = function () { + process.stdout.write("Username: "); + awaiter = withUser; + } + + promptUser(); } module.exports = { From abcdb4ad256ddfbacf9c9d087bb25213940ff718 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 5 Mar 2018 10:44:33 -0500 Subject: [PATCH 0222/1008] Attempting to use LoginManager to run octorun --- octorun/bin/octorun | 2 +- octorun/src/bin/app-login.js | 10 +++++----- octorun/src/bin/app-organizations.js | 4 ++-- octorun/src/bin/app-publish.js | 6 +++--- octorun/src/bin/app-usage.js | 2 +- octorun/src/bin/app-validate.js | 4 ++-- octorun/src/configuration.js | 2 +- src/GitHub.Api/Authentication/LoginManager.cs | 14 ++++++++++---- 8 files changed, 25 insertions(+), 19 deletions(-) diff --git a/octorun/bin/octorun b/octorun/bin/octorun index f7c15dc90..9c031d64f 100644 --- a/octorun/bin/octorun +++ b/octorun/bin/octorun @@ -1,5 +1,5 @@ #!/usr/bin/env node -console.log("node:", process.argv[0]); +process.stdout.write("node:", process.argv[0]); require('../src/bin/app.js'); diff --git a/octorun/src/bin/app-login.js b/octorun/src/bin/app-login.js index 19f2582fd..f90504f25 100644 --- a/octorun/src/bin/app-login.js +++ b/octorun/src/bin/app-login.js @@ -9,22 +9,22 @@ commander if (commander.twoFactor) { authentication.handleTwoFactorAuthentication(function (token) { - console.log(token); + process.stdout.write(token); process.exit(); }, function (err) { - console.log(err); + process.stdout.write(err); process.exit(); }); } else { authentication.handleBasicAuthentication(function (token) { - console.log(token); + process.stdout.write(token); process.exit(); }, function () { - console.log("Must specify two-factor authentication OTP code."); + process.stdout.write("Must specify two-factor authentication OTP code."); process.exit(); }, function (err) { - console.log(err); + process.stdout.write(err); process.exit(); }); } \ No newline at end of file diff --git a/octorun/src/bin/app-organizations.js b/octorun/src/bin/app-organizations.js index e57acc8d3..21a9b86ed 100644 --- a/octorun/src/bin/app-organizations.js +++ b/octorun/src/bin/app-organizations.js @@ -9,11 +9,11 @@ commander var apiWrapper = new ApiWrapper(); apiWrapper.getOrgs(function (error, result) { if (error) { - console.log(error); + process.stdout.write(error); process.exit(-1); } else { - console.log(result); + process.stdout.write(result); process.exit(); } }); \ No newline at end of file diff --git a/octorun/src/bin/app-publish.js b/octorun/src/bin/app-publish.js index a02033276..69757ee51 100644 --- a/octorun/src/bin/app-publish.js +++ b/octorun/src/bin/app-publish.js @@ -12,7 +12,7 @@ commander if(!commander.repository) { - console.log("repository required"); + process.stdout.write("repository required"); commander.help(); process.exit(-1); return; @@ -28,11 +28,11 @@ var apiWrapper = new ApiWrapper(); apiWrapper.publish(commander.repository, commander.description, private, commander.organization, function (error, result) { if (error) { - console.log(error); + process.stdout.write(error); process.exit(-1); } else { - console.log(result); + process.stdout.write(result); process.exit(); } }); \ No newline at end of file diff --git a/octorun/src/bin/app-usage.js b/octorun/src/bin/app-usage.js index c3f6ea5f6..a6279e411 100644 --- a/octorun/src/bin/app-usage.js +++ b/octorun/src/bin/app-usage.js @@ -21,7 +21,7 @@ var options = { }; var req = https.request(options, function (res) { - console.log('statusCode:', res.statusCode); + process.stdout.write('statusCode:', res.statusCode); res.on('data', function (d) { process.stdout.write(d); diff --git a/octorun/src/bin/app-validate.js b/octorun/src/bin/app-validate.js index 5e63750bd..55c5bf766 100644 --- a/octorun/src/bin/app-validate.js +++ b/octorun/src/bin/app-validate.js @@ -10,11 +10,11 @@ var apiWrapper = new ApiWrapper(); apiWrapper.verifyUser(function (error, result) { if (error) { - console.log(error); + process.stdout.write(error); process.exit(-1); } else { - console.log(result); + process.stdout.write(result); process.exit(); } }); \ No newline at end of file diff --git a/octorun/src/configuration.js b/octorun/src/configuration.js index 4d9474b40..ba5ad4447 100644 --- a/octorun/src/configuration.js +++ b/octorun/src/configuration.js @@ -1,4 +1,4 @@ -require("dotenv").config(); +require("dotenv").config({silent: true}); var clientId = process.env.OCTOKIT_CLIENT_ID; var clientSecret = process.env.OCTOKIT_CLIENT_SECRET; diff --git a/src/GitHub.Api/Authentication/LoginManager.cs b/src/GitHub.Api/Authentication/LoginManager.cs index fd83383d5..ffed03457 100644 --- a/src/GitHub.Api/Authentication/LoginManager.cs +++ b/src/GitHub.Api/Authentication/LoginManager.cs @@ -259,7 +259,7 @@ private async Task TryLogin( string password ) { - logger.Info("Login Username:{0} {1}", username, octorunScript); + logger.Info("Login Username:{0} Script:{1}", username, octorunScript); ApplicationAuthorization auth = null; var loginTask = new SimpleListProcessTask(taskManager.Token, nodeJsExecutablePath, $"{octorunScript} login"); @@ -270,11 +270,17 @@ string password proc.StandardInput.WriteLine(password); proc.StandardInput.Close(); }; - var ret = await loginTask.StartAwait(); - foreach (var result in ret) + loginTask.OnEndProcess += proc => { + logger.Trace("Exit Code: ", proc.Process.ExitCode); + }; + + var ret = (await loginTask.StartAwait()).ToArray(); + + for (var index = 0; index < ret.Length; index++) { - logger.Trace(result); + var result = ret[index]; + logger.Trace("line {0}: {1}", index, result); } throw new Exception("Authentication failed"); From 95f1cb7af208982d7e920604dd84b04cd06a58f8 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 17:09:46 +0100 Subject: [PATCH 0223/1008] Fix a bunch of bugs in the git installation sequence and update progress --- .../Application/ApplicationManagerBase.cs | 21 +- src/GitHub.Api/Helpers/Progress.cs | 21 +- src/GitHub.Api/IO/Utils.cs | 2 - src/GitHub.Api/Installer/GitInstaller.cs | 352 ++++++++++-------- src/GitHub.Api/Installer/IZipHelper.cs | 2 +- src/GitHub.Api/Installer/UnzipTask.cs | 25 +- src/GitHub.Api/Installer/ZipHelper.cs | 56 ++- src/GitHub.Api/Tasks/DownloadTask.cs | 2 +- src/GitHub.Api/Tasks/TaskBase.cs | 21 +- .../Assets/Editor/GitHub.Unity/UI/Spinner.cs | 6 +- .../Assets/Editor/GitHub.Unity/UI/Window.cs | 4 +- .../BasePlatformIntegrationTest.cs | 21 +- .../Installer/GitInstallerTests.cs | 25 +- src/tests/IntegrationTests/UnzipTaskTests.cs | 2 +- 14 files changed, 307 insertions(+), 253 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index c1e2112ef..418b5662f 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -12,11 +12,17 @@ abstract class ApplicationManagerBase : IApplicationManager protected static ILogging Logger { get; } = LogHelper.GetLogger(); private RepositoryManager repositoryManager; + private Progress progressReporter; protected bool isBusy; - public event Action OnProgress; + public event Action OnProgress + { + add { progressReporter.OnProgress += value; } + remove { progressReporter.OnProgress -= value; } + } public ApplicationManagerBase(SynchronizationContext synchronizationContext) { + progressReporter = new Progress(); SynchronizationContext = synchronizationContext; SynchronizationContext.SetSynchronizationContext(SynchronizationContext); ThreadingHelper.SetUIThread(); @@ -60,7 +66,8 @@ public void Run(bool firstRun) Logger.Trace("No git path found in settings"); isBusy = true; - var initEnvironmentTask = new ActionTask(CancellationToken, (b, path) => InitializeEnvironment(path)) { Affinity = TaskAffinity.UI }; + var initEnvironmentTask = new ActionTask(CancellationToken, + (b, path) => InitializeEnvironment(path)) { Affinity = TaskAffinity.UI }; var findExecTask = new FindExecTask("git", CancellationToken) .FinallyInUI((b, ex, path) => { @@ -80,7 +87,15 @@ public void Run(bool firstRun) var gitInstaller = new GitInstaller(Environment, CancellationToken); // if successful, continue with environment initialization, otherwise try to find an existing git installation - gitInstaller.SetupGitIfNeeded(initEnvironmentTask, findExecTask); + var setupTask = gitInstaller.SetupGitIfNeeded(); + setupTask.Progress(progressReporter.UpdateProgress); + setupTask.OnEnd += (thisTask, result, success, exception) => + { + if (success && result != null) + thisTask.Then(initEnvironmentTask); + else + thisTask.Then(findExecTask); + }; } } diff --git a/src/GitHub.Api/Helpers/Progress.cs b/src/GitHub.Api/Helpers/Progress.cs index 7aadf605f..4dc90a4a9 100644 --- a/src/GitHub.Api/Helpers/Progress.cs +++ b/src/GitHub.Api/Helpers/Progress.cs @@ -1,3 +1,4 @@ +using GitHub.Logging; using System; namespace GitHub.Unity @@ -11,25 +12,41 @@ public interface IProgress float Percentage { get; } long Value { get; } long Total { get; } + string Message { get; } + event Action OnProgress; } public class Progress : IProgress { + private static ILogging Logger = LogHelper.GetLogger(); public ITask Task { get; internal set; } public float Percentage { get { return Total > 0 ? (float)(double)Value / Total : 0f; } } public long Value { get; internal set; } public long Total { get; internal set; } + public string Message { get; internal set; } private long previousValue; private float averageSpeed = -1f; private float lastSpeed = 0f; private float smoothing = 0.005f; + public event Action OnProgress; - public void UpdateProgress(long value, long total) + public void UpdateProgress(IProgress progress) + { + Task = progress.Task; + UpdateProgress(progress.Value, progress.Total, progress.Message); + } + + public void UpdateProgress(long value, long total, string message = null) { - previousValue = Value; Total = total; Value = value; + Message = message ?? Message; + if (Total == 0 || ((float)(double)Value / Total) - ((float)(double)previousValue / Total) > 1f / 100f) + { // signal progress in 1% increments or if we don't know what the total is + previousValue = Value; + OnProgress?.Invoke(this); + } } } } diff --git a/src/GitHub.Api/IO/Utils.cs b/src/GitHub.Api/IO/Utils.cs index 34fcccdf0..fb4358dd9 100644 --- a/src/GitHub.Api/IO/Utils.cs +++ b/src/GitHub.Api/IO/Utils.cs @@ -14,7 +14,6 @@ public static bool Copy(Stream source, Stream destination, Func progress = null, int progressUpdateRate = 100) { - var logger = LogHelper.GetLogger("Copy"); byte[] buffer = new byte[chunkSize]; int bytesRead = 0; long totalRead = 0; @@ -62,7 +61,6 @@ public static bool Copy(Stream source, Stream destination, timeToFinish = Math.Max(1L, (long)((totalSize - totalRead) / (averageSpeed / progressUpdateRate))); - logger.Trace($"totalRead: {totalRead} of {totalSize}"); success = progress(totalRead, timeToFinish); if (!success) break; diff --git a/src/GitHub.Api/Installer/GitInstaller.cs b/src/GitHub.Api/Installer/GitInstaller.cs index edd9f61cd..0bbd2680c 100644 --- a/src/GitHub.Api/Installer/GitInstaller.cs +++ b/src/GitHub.Api/Installer/GitInstaller.cs @@ -13,230 +13,260 @@ class GitInstaller private readonly IEnvironment environment; private readonly GitInstallDetails installDetails; private readonly IZipHelper sharpZipLibHelper; - private NPath gitArchiveFilePath; - private NPath gitLfsArchivePath; + + ITask installationTask; public GitInstaller(IEnvironment environment, CancellationToken cancellationToken, - GitInstallDetails installDetails = null, NPath gitArchiveFilePath = null, NPath gitLfsArchivePath = null) + GitInstallDetails installDetails = null) { this.environment = environment; this.sharpZipLibHelper = ZipHelper.Instance; this.cancellationToken = cancellationToken; this.installDetails = installDetails ?? new GitInstallDetails(environment.UserCachePath, environment.IsWindows); - this.gitArchiveFilePath = gitArchiveFilePath; - this.gitLfsArchivePath = gitLfsArchivePath; } - public void SetupGitIfNeeded(ActionTask onSuccess, ITask onFailure) + public ITask SetupGitIfNeeded() { Logger.Trace("SetupGitIfNeeded"); + installationTask = new FuncTask(cancellationToken, (_, r) => installDetails.GitExecutablePath) + { Name = "Git Installation - Complete" }; + installationTask.OnStart += thisTask => thisTask.UpdateProgress(0, 100); + installationTask.OnEnd += (thisTask, result, success, exception) => thisTask.UpdateProgress(100, 100); + if (!environment.IsWindows) - { - onFailure.Start(); - return; - } + return installationTask; - var isGitExtractedTask = new FuncTask(cancellationToken, () => - { - if (!IsGitExtracted()) + var startTask = new FuncTask(cancellationToken, () => { - GrabZipFromResources(); - return null; - } - Logger.Trace("SetupGitIfNeeded: Skipped"); - return installDetails.GitExecutablePath; - }); - isGitExtractedTask.OnEnd += (t, res, _, __) => + var state = VerifyGitInstallation(); + if (!state.GitIsValid && !state.GitLfsIsValid) + state = GrabZipFromResources(state); + else + Logger.Trace("SetupGitIfNeeded: Skipped"); + return state; + }) + { Name = "Git Installation - Extract" }; + + + startTask.OnEnd += (thisTask, state, success, exception) => { - if (res == null) + if (!state.GitIsValid && !state.GitLfsIsValid) { - var extractTask = ExtractPortableGit(); - extractTask.Then(onSuccess, TaskRunOptions.OnSuccess, taskIsTopOfChain: true); - extractTask.Then(onFailure, TaskRunOptions.OnFailure, taskIsTopOfChain: true); - t.Then(extractTask); + if (!state.GitZipExists || !state.GitLfsZipExists) + thisTask = thisTask.Then(CreateDownloadTask(state)); + thisTask = thisTask.Then(ExtractPortableGit(state)); } - else - t.Then(onSuccess); + thisTask.Then(installationTask); }; - isGitExtractedTask.Start(); + // we want to start the startTask and not the installationTask because the latter only gets + // appended to the task chain when startTask ends, so calling Start() on it wouldn't work + startTask.Start(); + return installationTask; } - private void GrabZipFromResources() + private GitInstallationState VerifyGitInstallation() { - if (gitArchiveFilePath == null || !gitArchiveFilePath.FileExists()) - gitArchiveFilePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", installDetails.ZipPath, environment); - if (!gitArchiveFilePath.FileExists()) - gitArchiveFilePath = null; - - if (gitLfsArchivePath == null || !gitLfsArchivePath.FileExists()) - gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", installDetails.ZipPath, environment); - if (!gitLfsArchivePath.FileExists()) - gitLfsArchivePath = null; + var state = new GitInstallationState(); + state.GitExists = installDetails.GitExecutablePath?.FileExists() ?? false; + state.GitLfsExists = installDetails.GitLfsExecutablePath?.FileExists() ?? false; + state.GitZipExists = installDetails.GitZipPath.FileExists(); + state.GitLfsZipExists = installDetails.GitLfsZipPath.FileExists(); + + if (state.GitExists) + { + var actualmd5 = installDetails.GitExecutablePath.CalculateMD5(); + var expectedmd5 = environment.IsWindows ? GitInstallDetails.WindowsGitExecutableMD5 : GitInstallDetails.MacGitExecutableMD5; + state.GitIsValid = expectedmd5.Equals(actualmd5, StringComparison.InvariantCultureIgnoreCase); + if (!state.GitIsValid) + Logger.Trace($"Path {installDetails.GitExecutablePath} has MD5 {actualmd5} expected {expectedmd5}"); + } + else + Logger.Trace($"{installDetails.GitExecutablePath} does not exist"); + + if (state.GitLfsExists) + { + var actualmd5 = installDetails.GitLfsExecutablePath.CalculateMD5(); + var expectedmd5 = environment.IsWindows ? GitInstallDetails.WindowsGitLfsExecutableMD5 : GitInstallDetails.MacGitLfsExecutableMD5; + state.GitLfsIsValid = expectedmd5.Equals(actualmd5, StringComparison.InvariantCultureIgnoreCase); + if (!state.GitLfsIsValid) + Logger.Trace($"Path {installDetails.GitLfsExecutablePath} has MD5 {actualmd5} expected {expectedmd5}"); + } + else + Logger.Trace($"{installDetails.GitLfsExecutablePath} does not exist"); + installationTask.UpdateProgress(10, 100); + return state; } - private ITask CreateDownloadTask() + private GitInstallationState GrabZipFromResources(GitInstallationState state) { - gitArchiveFilePath = installDetails.ZipPath.Combine("git.zip"); - gitLfsArchivePath = installDetails.ZipPath.Combine("git-lfs.zip"); + if (!state.GitZipExists) + AssemblyResources.ToFile(ResourceType.Platform, "git.zip", installDetails.ZipPath, environment); + state.GitZipExists = installDetails.GitZipPath.FileExists(); + + if (!state.GitLfsZipExists) + AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", installDetails.ZipPath, environment); + state.GitLfsZipExists = installDetails.GitLfsZipPath.FileExists(); + installationTask.UpdateProgress(20, 100); + return 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; - } - - private FuncTask CreateUnzipTasks(NPath gitExtractPath, NPath gitLfsExtractPath, NPath tempZipExtractPath) - { - var unzipGitTask = new UnzipTask(cancellationToken, gitArchiveFilePath, gitExtractPath, sharpZipLibHelper, - environment.FileSystem, GitInstallDetails.GitExtractedMD5); - var unzipGitLfsTask = new UnzipTask(cancellationToken, gitLfsArchivePath, gitLfsExtractPath, sharpZipLibHelper, - environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5); - - var moveGitTask = new FuncTask(cancellationToken, () => MoveGitAndLfs(gitExtractPath, gitLfsExtractPath, tempZipExtractPath)); - return unzipGitTask - .Then(unzipGitLfsTask) - .Then(moveGitTask); + return downloader.Then((_, data) => + { + state.GitZipExists = installDetails.GitZipPath.FileExists(); + state.GitLfsZipExists = installDetails.GitLfsZipPath.FileExists(); + installationTask.UpdateProgress(40, 100); + return state; + }); } - private FuncTask ExtractPortableGit() + private FuncTask ExtractPortableGit(GitInstallationState state) { + ITask task = null; var tempZipExtractPath = NPath.CreateTempDirectory("git_zip_extract_zip_paths"); var gitExtractPath = tempZipExtractPath.Combine("git").CreateDirectory(); - var gitLfsExtractPath = tempZipExtractPath.Combine("git-lfs").CreateDirectory(); - - var unzipTasks = CreateUnzipTasks(gitExtractPath, gitLfsExtractPath, tempZipExtractPath); - if (gitArchiveFilePath == null || gitLfsArchivePath == null) + if (!state.GitIsValid) { - var downloadFilesTask = CreateDownloadTask(); - unzipTasks = downloadFilesTask.Then(unzipTasks); - } - - return unzipTasks; - } - - private NPath MoveGitAndLfs(NPath gitExtractPath, NPath gitLfsExtractPath, NPath tempZipExtractPath) - { - var targetGitLfsExecPath = installDetails.GetGitLfsExecutablePath(gitExtractPath); - var extractGitLfsExePath = gitLfsExtractPath.Combine(installDetails.GitLfsExecutable); - - Logger.Trace($"Moving Git LFS Exe:'{extractGitLfsExePath}' to target in tempDirectory:'{targetGitLfsExecPath}'"); + ITask unzipTask = new UnzipTask(cancellationToken, installDetails.GitZipPath, gitExtractPath, sharpZipLibHelper, + environment.FileSystem, GitInstallDetails.GitExtractedMD5); + unzipTask.Progress(p => installationTask.UpdateProgress(40 + (long)(20 * p.Percentage), 100, unzipTask.Name)); - extractGitLfsExePath.Move(targetGitLfsExecPath); - - Logger.Trace($"Moving tempDirectory:'{gitExtractPath}' to extractTarget:'{installDetails.GitInstallationPath}'"); + unzipTask = unzipTask.Then((s, 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; + return path; + }); + task = unzipTask; + } - installDetails.GitInstallationPath.EnsureParentDirectoryExists(); - gitExtractPath.Move(installDetails.GitInstallationPath); + var gitLfsExtractPath = tempZipExtractPath.Combine("git-lfs").CreateDirectory(); - Logger.Trace($"Deleting targetGitLfsExecPath:'{targetGitLfsExecPath}'"); + if (!state.GitLfsIsValid) + { + ITask unzipTask = new UnzipTask(cancellationToken, installDetails.GitLfsZipPath, gitLfsExtractPath, sharpZipLibHelper, + environment.FileSystem, GitInstallDetails.GitLfsExtractedMD5); + unzipTask.Progress(p => installationTask.UpdateProgress(60 + (long)(20 * p.Percentage), 100, unzipTask.Name)); - targetGitLfsExecPath.DeleteIfExists(); + unzipTask = unzipTask.Then((s, 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; + return path; + }); + task = task?.Then(unzipTask) ?? unzipTask; + } - Logger.Trace($"Deleting tempZipPath:'{tempZipExtractPath}'"); - tempZipExtractPath.DeleteIfExists(); - return installDetails.GitExecutablePath; + return task.Finally(new FuncTask(cancellationToken, (success) => + { + tempZipExtractPath.DeleteIfExists(); + return state; + })); } - private bool IsGitExtracted() + class GitInstallationState { - if (!installDetails.GitInstallationPath.DirectoryExists()) - { - Logger.Warning($"{installDetails.GitInstallationPath} does not exist"); - return false; - } - - var gitExecutableMd5 = installDetails.GitExecutablePath.CalculateMD5(); - var expectedGitExecutableMd5 = environment.IsWindows ? GitInstallDetails.WindowsGitExecutableMD5 : GitInstallDetails.MacGitExecutableMD5; - - if (!expectedGitExecutableMd5.Equals(gitExecutableMd5, StringComparison.InvariantCultureIgnoreCase)) - { - Logger.Warning($"Path {installDetails.GitExecutablePath} has MD5 {gitExecutableMd5} expected {expectedGitExecutableMd5}"); - return false; - } + 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; } + } - var gitLfsExecutableMd5 = installDetails.GitLfsExecutablePath.CalculateMD5(); - var expectedGitLfsExecutableMd5 = environment.IsWindows ? GitInstallDetails.WindowsGitLfsExecutableMD5 : GitInstallDetails.MacGitLfsExecutableMD5; + public class GitInstallDetails + { + public const string DefaultGitZipMd5Url = "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt"; + 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.txt"; + public const string DefaultGitLfsZipUrl = "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip"; - if (!expectedGitLfsExecutableMd5.Equals(gitLfsExecutableMd5, StringComparison.InvariantCultureIgnoreCase)) - { - Logger.Warning($"Path {installDetails.GitLfsExecutablePath} has MD5 {gitLfsExecutableMd5} expected {expectedGitLfsExecutableMd5}"); - return false; - } + public const string GitExtractedMD5 = "e6cfc0c294a2312042f27f893dfc9c0a"; + public const string GitLfsExtractedMD5 = "36e3ae968b69fbf42dff72311040d24a"; - Logger.Trace("Git Present"); - return true; - } + public const string WindowsGitExecutableMD5 = "50570ed932559f294d1a1361801740b9"; + public const string MacGitExecutableMD5 = ""; - public class GitInstallDetails - { - public const string DefaultGitZipMd5Url = "https://ghfvs-installer.github.com/unity/portable_git/git.zip.MD5.txt"; - 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.txt"; - public const string DefaultGitLfsZipUrl = "https://ghfvs-installer.github.com/unity/portable_git/git-lfs.zip"; + public const string WindowsGitLfsExecutableMD5 = "177bb14d0c08f665a24f0d5516c3b080"; + public const string MacGitLfsExecutableMD5 = "f81a1a065a26a4123193e8fd96c561ad"; - public const string GitExtractedMD5 = "e6cfc0c294a2312042f27f893dfc9c0a"; - public const string GitLfsExtractedMD5 = "36e3ae968b69fbf42dff72311040d24a"; + private const string PackageVersion = "f02737a78695063deace08e96d5042710d3e32db"; + private const string PackageName = "PortableGit"; - public const string WindowsGitExecutableMD5 = "50570ed932559f294d1a1361801740b9"; - public const string MacGitExecutableMD5 = ""; + private const string gitZip = "git.zip"; + private const string gitLfsZip = "git-lfs.zip"; - public const string WindowsGitLfsExecutableMD5 = "177bb14d0c08f665a24f0d5516c3b080"; - public const string MacGitLfsExecutableMD5 = "f81a1a065a26a4123193e8fd96c561ad"; + private readonly bool onWindows; - private const string PackageVersion = "f02737a78695063deace08e96d5042710d3e32db"; - private const string PackageName = "PortableGit"; + public GitInstallDetails(NPath baseDataPath, bool onWindows) + { + this.onWindows = onWindows; - private readonly bool onWindows; + ZipPath = baseDataPath.Combine("downloads"); + ZipPath.EnsureDirectoryExists(); + GitZipPath = ZipPath.Combine(gitZip); + GitLfsZipPath = ZipPath.Combine(gitLfsZip); - public GitInstallDetails(NPath baseDataPath, bool onWindows) - { - this.onWindows = onWindows; + var gitInstallPath = baseDataPath.Combine(PackageNameWithVersion); + GitInstallationPath = gitInstallPath; - ZipPath = baseDataPath.Combine("downloads"); - ZipPath.EnsureDirectoryExists(); + if (onWindows) + { + GitExecutable += "git.exe"; + GitLfsExecutable += "git-lfs.exe"; - var gitInstallPath = baseDataPath.Combine(PackageNameWithVersion); - GitInstallationPath = gitInstallPath; + GitExecutablePath = gitInstallPath.Combine("cmd", GitExecutable); + } + else + { + GitExecutable = "git"; + GitLfsExecutable = "git-lfs"; - if (onWindows) - { - GitExecutable += "git.exe"; - GitLfsExecutable += "git-lfs.exe"; + GitExecutablePath = gitInstallPath.Combine("bin", GitExecutable); + } - GitExecutablePath = gitInstallPath.Combine("cmd", GitExecutable); + GitLfsExecutablePath = GetGitLfsExecutablePath(gitInstallPath); } - else - { - GitExecutable = "git"; - GitLfsExecutable = "git-lfs"; - GitExecutablePath = gitInstallPath.Combine("bin", GitExecutable); + public NPath GetGitLfsExecutablePath(NPath gitInstallRoot) + { + return onWindows + ? gitInstallRoot.Combine("mingw32", "libexec", "git-core", GitLfsExecutable) + : gitInstallRoot.Combine("libexec", "git-core", GitLfsExecutable); } - GitLfsExecutablePath = GetGitLfsExecutablePath(gitInstallPath); - } - - public NPath GetGitLfsExecutablePath(NPath gitInstallRoot) - { - return onWindows - ? gitInstallRoot.Combine("mingw32", "libexec", "git-core", GitLfsExecutable) - : gitInstallRoot.Combine("libexec", "git-core", GitLfsExecutable); + public NPath ZipPath { get; } + public NPath GitZipPath { get; } + public NPath GitLfsZipPath { get; } + public NPath GitInstallationPath { get; } + public string GitExecutable { get; } + public NPath GitExecutablePath { get; } + public string GitLfsExecutable { get; } + public NPath GitLfsExecutablePath { get; } + public UriString GitZipMd5Url { get; set; } = DefaultGitZipMd5Url; + public UriString GitZipUrl { get; set; } = DefaultGitZipUrl; + public UriString GitLfsZipMd5Url { get; set; } = DefaultGitLfsZipMd5Url; + public UriString GitLfsZipUrl { get; set; } = DefaultGitLfsZipUrl; + public string PackageNameWithVersion => PackageName + "_" + PackageVersion; } - - public NPath ZipPath { get; } - public NPath GitInstallationPath { get; } - public string GitExecutable { get; } - public NPath GitExecutablePath { get; } - public string GitLfsExecutable { get; } - public NPath GitLfsExecutablePath { get; } - public UriString GitZipMd5Url { get; set; } = DefaultGitZipMd5Url; - public UriString GitZipUrl { get; set; } = DefaultGitZipUrl; - public UriString GitLfsZipMd5Url { get; set; } = DefaultGitLfsZipMd5Url; - public UriString GitLfsZipUrl { get; set; } = DefaultGitLfsZipUrl; - public string PackageNameWithVersion => PackageName + "_" + PackageVersion; } } -} diff --git a/src/GitHub.Api/Installer/IZipHelper.cs b/src/GitHub.Api/Installer/IZipHelper.cs index a536dcadf..969d9e35c 100644 --- a/src/GitHub.Api/Installer/IZipHelper.cs +++ b/src/GitHub.Api/Installer/IZipHelper.cs @@ -5,7 +5,7 @@ namespace GitHub.Unity { interface IZipHelper { - void Extract(string archive, string outFolder, CancellationToken cancellationToken, + bool Extract(string archive, string outFolder, CancellationToken cancellationToken, Func onProgress = null); } } diff --git a/src/GitHub.Api/Installer/UnzipTask.cs b/src/GitHub.Api/Installer/UnzipTask.cs index 13620cd45..012fc6629 100644 --- a/src/GitHub.Api/Installer/UnzipTask.cs +++ b/src/GitHub.Api/Installer/UnzipTask.cs @@ -4,7 +4,7 @@ namespace GitHub.Unity { - class UnzipTask: TaskBase + class UnzipTask : TaskBase { private readonly string archiveFilePath; private readonly NPath extractedPath; @@ -12,13 +12,13 @@ class UnzipTask: TaskBase private readonly IFileSystem fileSystem; private readonly string expectedMD5; - public UnzipTask(CancellationToken token, string archiveFilePath, NPath extractedPath, IFileSystem fileSystem, string expectedMD5 = null) : + public UnzipTask(CancellationToken token, NPath archiveFilePath, NPath extractedPath, IFileSystem fileSystem, string expectedMD5 = null) : this(token, archiveFilePath, extractedPath, ZipHelper.Instance, fileSystem, expectedMD5) { } - public UnzipTask(CancellationToken token, string archiveFilePath, NPath extractedPath, IZipHelper zipHelper, IFileSystem fileSystem, string expectedMD5 = null) + public UnzipTask(CancellationToken token, NPath archiveFilePath, NPath extractedPath, IZipHelper zipHelper, IFileSystem fileSystem, string expectedMD5 = null) : base(token) { this.archiveFilePath = archiveFilePath; @@ -26,22 +26,23 @@ public UnzipTask(CancellationToken token, string archiveFilePath, NPath extracte this.zipHelper = zipHelper; this.fileSystem = fileSystem; this.expectedMD5 = expectedMD5; + Name = $"Unzip {archiveFilePath.FileName}"; } - protected void BaseRun(bool success) + protected NPath BaseRun(bool success) { - base.Run(success); + return base.RunWithReturn(success); } - protected override void Run(bool success) + protected override NPath RunWithReturn(bool success) { - BaseRun(success); + var ret = BaseRun(success); RaiseOnStart(); try { - RunUnzip(success); + ret = RunUnzip(success); } catch (Exception ex) { @@ -51,11 +52,12 @@ protected override void Run(bool success) } finally { - RaiseOnEnd(); + RaiseOnEnd(ret); } + return ret; } - protected virtual void RunUnzip(bool success) + protected virtual NPath RunUnzip(bool success) { Logger.Trace("Unzip File: {0} to Path: {1}", archiveFilePath, extractedPath); @@ -69,7 +71,7 @@ protected virtual void RunUnzip(bool success) exception = null; try { - zipHelper.Extract(archiveFilePath, extractedPath, Token, zipFileProgress, estimatedDurationProgress); + success = zipHelper.Extract(archiveFilePath, extractedPath, Token, (value, total) => { UpdateProgress(value, total); @@ -103,6 +105,7 @@ protected virtual void RunUnzip(bool success) Token.ThrowIfCancellationRequested(); throw new UnzipException("Error unzipping file", exception); } + return extractedPath; } protected int RetryCount { get; } } diff --git a/src/GitHub.Api/Installer/ZipHelper.cs b/src/GitHub.Api/Installer/ZipHelper.cs index 2e37a952a..769a34b74 100644 --- a/src/GitHub.Api/Installer/ZipHelper.cs +++ b/src/GitHub.Api/Installer/ZipHelper.cs @@ -3,6 +3,8 @@ using System.IO; using System.Threading; using ICSharpCode.SharpZipLib.Zip; +using GitHub.Logging; +using System.Collections.Generic; namespace GitHub.Unity { @@ -23,18 +25,17 @@ public static IZipHelper Instance } } - public void Extract(string archive, string outFolder, CancellationToken cancellationToken, + public bool Extract(string archive, string outFolder, CancellationToken cancellationToken, Func onProgress = null) { - ExtractZipFile(archive, outFolder, cancellationToken, onProgress); + return ExtractZipFile(archive, outFolder, cancellationToken, onProgress); } - public static void ExtractZipFile(string archive, string outFolder, CancellationToken cancellationToken, + public static bool ExtractZipFile(string archive, string outFolder, CancellationToken cancellationToken, Func onProgress) { const int chunkSize = 4096; // 4K is optimum ZipFile zf = null; - var startTime = DateTime.Now; var processed = 0; var totalBytes = 0L; @@ -42,15 +43,23 @@ public static void ExtractZipFile(string archive, string outFolder, Cancellation { var fs = File.OpenRead(archive); zf = new ZipFile(fs); - var totalSize = fs.Length; + long totalSize = 0; + var entries = new List((int)zf.Count); foreach (ZipEntry zipEntry in zf) { - cancellationToken.ThrowIfCancellationRequested(); if (zipEntry.IsDirectory) { continue; // Ignore directories } + entries.Add(zipEntry); + totalSize += zipEntry.Size; + } + + for (var i = 0; i < entries.Count; i++) + { + var zipEntry = entries[i]; + cancellationToken.ThrowIfCancellationRequested(); var entryFileName = zipEntry.Name; // to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName); @@ -65,18 +74,18 @@ public static void ExtractZipFile(string archive, string outFolder, Cancellation { Directory.CreateDirectory(directoryName); } -//#if !WINDOWS -// if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX) -// { -// if (zipEntry.ExternalFileAttributes > 0) -// { -// int fd = Mono.Unix.Native.Syscall.open(fullZipToPath, -// Mono.Unix.Native.OpenFlags.O_CREAT | Mono.Unix.Native.OpenFlags.O_TRUNC, -// (Mono.Unix.Native.FilePermissions)zipEntry.ExternalFileAttributes); -// Mono.Unix.Native.Syscall.close(fd); -// } -// } -//#endif + //#if !WINDOWS + // if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX) + // { + // if (zipEntry.ExternalFileAttributes > 0) + // { + // int fd = Mono.Unix.Native.Syscall.open(fullZipToPath, + // Mono.Unix.Native.OpenFlags.O_CREAT | Mono.Unix.Native.OpenFlags.O_TRUNC, + // (Mono.Unix.Native.FilePermissions)zipEntry.ExternalFileAttributes); + // Mono.Unix.Native.Syscall.close(fd); + // } + // } + //#endif // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size // of the file, but does not waste memory. @@ -85,17 +94,23 @@ public static void ExtractZipFile(string archive, string outFolder, Cancellation using (var streamWriter = targetFile.OpenWrite()) { if (!Utils.Copy(zipStream, streamWriter, zipEntry.Size, chunkSize, - progress: (totalRead, timeToFinish) => { + progress: (totalRead, timeToFinish) => + { totalBytes += totalRead; return onProgress(totalBytes, totalSize); })) - return; + return false; } targetFile.LastWriteTime = zipEntry.DateTime; processed++; } } + catch (Exception ex) + { + LogHelper.GetLogger().Error(ex); + return false; + } finally { if (zf != null) @@ -104,6 +119,7 @@ public static void ExtractZipFile(string archive, string outFolder, Cancellation zf.Close(); // Ensure we release resources } } + return true; } } } diff --git a/src/GitHub.Api/Tasks/DownloadTask.cs b/src/GitHub.Api/Tasks/DownloadTask.cs index b253c0ec8..b66bd1d60 100644 --- a/src/GitHub.Api/Tasks/DownloadTask.cs +++ b/src/GitHub.Api/Tasks/DownloadTask.cs @@ -41,7 +41,7 @@ public DownloadTask(CancellationToken token, Url = url; Filename = filename ?? url.Filename; TargetDirectory = targetDirectory ?? NPath.CreateTempDirectory("ghu"); - Name = nameof(DownloadTask); + this.Name = $"Download {Url}"; } protected string BaseRunWithReturn(bool success) diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index a86bb48f2..efea6e506 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -28,7 +28,7 @@ public interface ITask : IAsyncResult /// /// Run another task at the end of the task execution, on a separate thread, regardless of execution state /// - ITask Finally(T taskToContinueWith) where T : ITask; + T Finally(T taskToContinueWith) where T : ITask; ITask Start(); ITask Start(TaskScheduler scheduler); ITask Progress(Action progressHandler); @@ -48,6 +48,8 @@ public interface ITask : IAsyncResult /// /// true if any task on the chain is marked as exclusive bool IsChainExclusive(); + + void UpdateProgress(long value, long total, string message = null); } public interface ITask : ITask @@ -101,9 +103,8 @@ public abstract class TaskBase : ITask protected event Func catchHandler; private event Action finallyHandler; - protected event Action progressHandler; - private Progress progress; + protected Progress progress; protected TaskBase(CancellationToken token) : this() @@ -236,14 +237,14 @@ public ITask Finally(Action actionToContinueWith, TaskAffinity /// /// Run another task at the end of the task execution, on a separate thread, regardless of execution state /// - public ITask Finally(T taskToContinueWith) + public T Finally(T taskToContinueWith) where T : ITask { Guard.ArgumentNotNull(taskToContinueWith, nameof(taskToContinueWith)); continuationOnAlways = (TaskBase)(object)taskToContinueWith; continuationOnAlways.SetDependsOn(this); DependsOn?.SetFaultHandler(continuationOnAlways); - return continuationOnAlways; + return taskToContinueWith; } /// @@ -266,7 +267,7 @@ internal void SetFaultHandler(TaskBase handler) public ITask Progress(Action handler) { Guard.ArgumentNotNull(handler, nameof(handler)); - this.progressHandler += handler; + progress.OnProgress += handler; return this; } @@ -437,10 +438,9 @@ protected Exception GetThrownException() return DependsOn.GetThrownException(); } - protected void UpdateProgress(long value, long total) + public void UpdateProgress(long value, long total, string message = null) { - progress.UpdateProgress(value, total); - progressHandler?.Invoke(progress); + progress.UpdateProgress(value, total, message); } public override string ToString() @@ -596,8 +596,7 @@ public ITask Finally(Action continuation, TaskAffinity /// public new ITask Progress(Action handler) { - Guard.ArgumentNotNull(handler, nameof(handler)); - this.progressHandler += handler; + base.Progress(handler); return this; } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Spinner.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Spinner.cs index 33bf1708a..3af1c08c7 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Spinner.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Spinner.cs @@ -130,10 +130,10 @@ public void Render() GUI.matrix = matrix; } - private void PushRotation(float rotation, Vector2 center) + private void PushRotation(float rotation, Vector2 rotCenter) { - rotations.Push(new Rotation(rotation, center)); - GUIUtility.RotateAroundPivot(rotation, center); + rotations.Push(new Rotation(rotation, rotCenter)); + GUIUtility.RotateAroundPivot(rotation, rotCenter); } private void PopRotation() diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs index 15ca9dc02..13a3d6118 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/Window.cs @@ -355,9 +355,9 @@ private void RepositoryOnCurrentBranchAndRemoteChanged(CacheUpdateEvent cacheUpd } } - private void OnProgress(IProgress progress) + private void OnProgress(IProgress progr) { - this.progress = progress; + progress = progr; } private void DetachHandlers(IRepository repository) diff --git a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs index f943fed7b..f0d4089f8 100644 --- a/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs +++ b/src/tests/IntegrationTests/BasePlatformIntegrationTest.cs @@ -33,22 +33,21 @@ protected void InitializePlatform(NPath repoPath, NPath environmentPath, bool en var installDetails = new GitInstaller.GitInstallDetails(applicationDataPath, true); var zipArchivesPath = TestBasePath.Combine("ZipArchives").CreateDirectory(); - var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); - var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); + AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); + AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); - var gitInstaller = new GitInstaller(Environment, TaskManager.Token, installDetails, gitArchivePath, gitLfsArchivePath); + var gitInstaller = new GitInstaller(Environment, TaskManager.Token, installDetails); NPath result = null; Exception ex = null; - gitInstaller.SetupGitIfNeeded(new ActionTask(TaskManager.Token, (b, path) => { - result = path; - autoResetEvent.Set(); - }), - new ActionTask(TaskManager.Token, (b, exception) => { - ex = exception; - autoResetEvent.Set(); - })); + var setupTask = gitInstaller.SetupGitIfNeeded(); + setupTask.OnEnd += (thisTask, path, success, exception) => + { + result = path; + ex = exception; + autoResetEvent.Set(); + }; autoResetEvent.WaitOne(); diff --git a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs index e13cde9a8..2d3d0b198 100644 --- a/src/tests/IntegrationTests/Installer/GitInstallerTests.cs +++ b/src/tests/IntegrationTests/Installer/GitInstallerTests.cs @@ -50,34 +50,11 @@ public void GitInstallTest() TestBasePath.Combine("git").CreateDirectory(); - //var gitArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git.zip", zipArchivesPath, Environment); - //var gitLfsArchivePath = AssemblyResources.ToFile(ResourceType.Platform, "git-lfs.zip", zipArchivesPath, Environment); - var gitInstaller = new GitInstaller(Environment, CancellationToken.None, installDetails); - var autoResetEvent = new AutoResetEvent(false); - - bool? result = null; NPath resultPath = null; - Exception ex = null; - - gitInstaller.SetupGitIfNeeded(new ActionTask(CancellationToken.None, (b, path) => { - result = true; - resultPath = path; - autoResetEvent.Set(); - }), - new ActionTask(CancellationToken.None, (b, exception) => { - result = false; - ex = exception; - autoResetEvent.Set(); - })); - - autoResetEvent.WaitOne(); - - result.HasValue.Should().BeTrue(); - result.Value.Should().BeTrue(); + Assert.DoesNotThrow(async () => resultPath = await gitInstaller.SetupGitIfNeeded().Task); resultPath.Should().NotBeNull(); - ex.Should().BeNull(); } } } \ No newline at end of file diff --git a/src/tests/IntegrationTests/UnzipTaskTests.cs b/src/tests/IntegrationTests/UnzipTaskTests.cs index 0aac87a1a..da788ec95 100644 --- a/src/tests/IntegrationTests/UnzipTaskTests.cs +++ b/src/tests/IntegrationTests/UnzipTaskTests.cs @@ -26,7 +26,7 @@ public async Task UnzipWorks() var extractedPath = TestBasePath.Combine("gitlfs_zip_extracted").CreateDirectory(); - var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, Environment.FileSystem, GitInstallDetails.GitExtractedMD5) + var unzipTask = new UnzipTask(CancellationToken.None, archiveFilePath, extractedPath, Environment.FileSystem, GitInstaller.GitInstallDetails.GitExtractedMD5) .Progress(p => { }); From 4c1d33c6cf75a734febc4673a7b93b9a94185467 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 17:18:08 +0100 Subject: [PATCH 0224/1008] This might be accessed before things have a chance to initialize --- src/GitHub.Api/Application/ApplicationManagerBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 418b5662f..c425c9322 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -247,7 +247,7 @@ public void Dispose() public ISettings SystemSettings { get; protected set; } public ISettings UserSettings { get; protected set; } public IUsageTracker UsageTracker { get; protected set; } - public bool IsBusy { get { return isBusy || RepositoryManager.IsBusy; } } + public bool IsBusy { get { return isBusy || (RepositoryManager?.IsBusy ?? false); } } protected TaskScheduler UIScheduler { get; private set; } protected SynchronizationContext SynchronizationContext { get; private set; } protected IRepositoryManager RepositoryManager { get { return repositoryManager; } } From a85058433934b016b4beabee9a3c741420bee3e1 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 17:18:15 +0100 Subject: [PATCH 0225/1008] Remove debug output --- src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs b/src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs index 47e2cd871..33c5576b8 100644 --- a/src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs +++ b/src/GitHub.Api/Tasks/ConcurrentExclusiveInterleave.cs @@ -158,8 +158,6 @@ internal void NotifyOfNewWork() /// This has been separated out into its own method to improve the Parallel Tasks window experience. private void ConcurrentExclusiveInterleaveProcessor() { - Logging.LogHelper.GetLogger().Trace("ConcurrentExclusiveInterleaveProcessor"); - if (token.IsCancellationRequested) return; interleaveTaskScheduler.ThreadToExclude = Thread.CurrentThread.ManagedThreadId; From 447fd9c188c17f54ae932481f3d9727a0a95497d Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 18:14:48 +0100 Subject: [PATCH 0226/1008] Replay any cache invalidation requests that happen before RepositoryManager is set --- .../Application/ApplicationManagerBase.cs | 1 + src/GitHub.Api/Git/IRepository.cs | 1 + src/GitHub.Api/Git/Repository.cs | 21 +++++++++++++++++-- src/GitHub.Api/Git/RepositoryManager.cs | 4 ++-- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index c425c9322..d0658227a 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -150,6 +150,7 @@ public void RestartRepository() repositoryManager.Initialize(); Environment.Repository.Initialize(repositoryManager); repositoryManager.Start(); + Environment.Repository.Start(); Logger.Trace($"Got a repository? {Environment.Repository}"); } } diff --git a/src/GitHub.Api/Git/IRepository.cs b/src/GitHub.Api/Git/IRepository.cs index 7acf918f0..46a959d87 100644 --- a/src/GitHub.Api/Git/IRepository.cs +++ b/src/GitHub.Api/Git/IRepository.cs @@ -78,5 +78,6 @@ public interface IRepository : IEquatable event Action LocksChanged; event Action RemoteBranchListChanged; event Action LocalAndRemoteBranchListChanged; + void Start(); } } \ No newline at end of file diff --git a/src/GitHub.Api/Git/Repository.cs b/src/GitHub.Api/Git/Repository.cs index 8157753d3..89e4f088a 100644 --- a/src/GitHub.Api/Git/Repository.cs +++ b/src/GitHub.Api/Git/Repository.cs @@ -15,6 +15,7 @@ class Repository : IEquatable, IRepository private ICacheContainer cacheContainer; private UriString cloneUrl; private string name; + private HashSet cacheInvalidationRequests = new HashSet(); public event Action LogChanged; public event Action TrackingStatusChanged; @@ -39,7 +40,7 @@ public Repository(NPath localPath, ICacheContainer container) LocalPath = localPath; cacheContainer = container; - cacheContainer.CacheInvalidated += CacheContainer_OnCacheInvalidated; + cacheContainer.CacheInvalidated += InvalidateCache; cacheContainer.CacheUpdated += CacheContainer_OnCacheUpdated; } @@ -58,6 +59,14 @@ public void Initialize(IRepositoryManager initRepositoryManager) repositoryManager.RemoteBranchesUpdated += RepositoryManagerOnRemoteBranchesUpdated; } + public void Start() + { + foreach (var req in cacheInvalidationRequests) + { + InvalidateCache(req); + } + } + public ITask SetupRemote(string remote, string remoteUrl) { Guard.ArgumentNotNullOrWhiteSpace(remote, "remote"); @@ -275,8 +284,16 @@ private void CheckBranchCacheEvent(CacheUpdateEvent cacheUpdateEvent) } } - private void CacheContainer_OnCacheInvalidated(CacheType cacheType) + private void InvalidateCache(CacheType cacheType) { + if (repositoryManager == null) + { + if (!cacheInvalidationRequests.Contains(cacheType)) + cacheInvalidationRequests.Add(cacheType); + return; + } + + switch (cacheType) { case CacheType.BranchCache: diff --git a/src/GitHub.Api/Git/RepositoryManager.cs b/src/GitHub.Api/Git/RepositoryManager.cs index cdbb4bff7..e70d587e7 100644 --- a/src/GitHub.Api/Git/RepositoryManager.cs +++ b/src/GitHub.Api/Git/RepositoryManager.cs @@ -42,11 +42,11 @@ public interface IRepositoryManager : IDisposable void UpdateGitAheadBehindStatus(); void UpdateLocks(); int WaitForEvents(); + void UpdateRepositoryInfo(); IGitConfig Config { get; } IGitClient GitClient { get; } bool IsBusy { get; } - void UpdateRepositoryInfo(); } interface IRepositoryPathConfiguration @@ -400,7 +400,7 @@ private ITask HookupHandlers(ITask task, bool filesystemChangesExpected) var isExclusive = task.IsChainExclusive(); task.GetTopOfChain().OnStart += t => { - if (t.Affinity == TaskAffinity.Exclusive) + if (isExclusive) { Logger.Trace("Starting Operation - Setting Busy Flag"); IsBusy = true; From 6d17c4ba6a13fd58e581d7ca90e43e0a2cadbe4f Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 18:52:05 +0100 Subject: [PATCH 0227/1008] Fix setting busy flag when tasks are done --- src/GitHub.Api/Tasks/ProcessTask.cs | 33 +++++++++++++++++++---------- src/GitHub.Api/Tasks/TaskBase.cs | 14 ++++++------ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/GitHub.Api/Tasks/ProcessTask.cs b/src/GitHub.Api/Tasks/ProcessTask.cs index f02821999..7388cd428 100644 --- a/src/GitHub.Api/Tasks/ProcessTask.cs +++ b/src/GitHub.Api/Tasks/ProcessTask.cs @@ -101,6 +101,8 @@ public void Run() try { + if (!Process.StartInfo.Arguments.StartsWith("credential-")) + Logger.Trace($"Running '{Process.StartInfo.FileName} {Process.StartInfo.Arguments}'"); Process.Start(); } catch (Win32Exception ex) @@ -286,20 +288,29 @@ protected override T RunWithReturn(bool success) RaiseOnStart, () => { - if (outputProcessor != null) - result = outputProcessor.Result; + try + { + if (outputProcessor != null) + result = outputProcessor.Result; - if (result == null && !Process.StartInfo.CreateNoWindow && typeof(T) == typeof(string)) - result = (T)(object)"Process running"; + if (result == null && !Process.StartInfo.CreateNoWindow && typeof(T) == typeof(string)) + result = (T)(object)"Process running"; - RaiseOnEnd(result); - - if (Errors != null) - { - OnErrorData?.Invoke(Errors); - thrownException = thrownException ?? new ProcessException(this); - if (!RaiseFaultHandlers(thrownException)) + if (Errors != null) + { + OnErrorData?.Invoke(Errors); + thrownException = thrownException ?? new ProcessException(this); throw thrownException; + } + } + catch (Exception ex) + { + if (!RaiseFaultHandlers(ex)) + throw ex; + } + finally + { + RaiseOnEnd(result); } }, (ex, error) => diff --git a/src/GitHub.Api/Tasks/TaskBase.cs b/src/GitHub.Api/Tasks/TaskBase.cs index efea6e506..42e5f7d25 100644 --- a/src/GitHub.Api/Tasks/TaskBase.cs +++ b/src/GitHub.Api/Tasks/TaskBase.cs @@ -387,16 +387,16 @@ protected virtual void RaiseOnEnd() OnEnd?.Invoke(this, !taskFailed, exception); if (!taskFailed || exceptionWasHandled) { - if (continuationOnSuccess == null && continuationOnAlways == null) + if (continuationOnSuccess == null) CallFinallyHandler(); - else if (continuationOnSuccess != null) + else SetContinuation(continuationOnSuccess, runOnSuccessOptions); } else { - if (continuationOnFailure == null && continuationOnAlways == null) + if (continuationOnFailure == null) CallFinallyHandler(); - else if (continuationOnFailure != null) + else SetContinuation(continuationOnFailure, runOnSuccessOptions); } //Logger.Trace($"Finished {ToString()}"); @@ -404,7 +404,7 @@ protected virtual void RaiseOnEnd() protected void CallFinallyHandler() { - finallyHandler?.Invoke(Task.Status == TaskStatus.RanToCompletion); + finallyHandler?.Invoke(!taskFailed); } protected virtual bool RaiseFaultHandlers(Exception ex) @@ -617,9 +617,9 @@ protected virtual void RaiseOnEnd(TResult data) { this.result = data; OnEnd?.Invoke(this, result, !taskFailed, exception); - if (continuationOnSuccess == null && continuationOnFailure == null && continuationOnAlways == null) + if (continuationOnSuccess == null && continuationOnFailure == null) { - finallyHandler?.Invoke(Task.Status == TaskStatus.RanToCompletion, result); + finallyHandler?.Invoke(!taskFailed, result); CallFinallyHandler(); } else if (continuationOnSuccess != null) From 95449aa1f803950ed95393540b6a2fc2c548d817 Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 5 Mar 2018 18:54:48 +0100 Subject: [PATCH 0228/1008] Fix the error and end pattern of process task --- src/GitHub.Api/Tasks/ProcessTask.cs | 33 ++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/GitHub.Api/Tasks/ProcessTask.cs b/src/GitHub.Api/Tasks/ProcessTask.cs index 7388cd428..894526044 100644 --- a/src/GitHub.Api/Tasks/ProcessTask.cs +++ b/src/GitHub.Api/Tasks/ProcessTask.cs @@ -306,7 +306,7 @@ protected override T RunWithReturn(bool success) catch (Exception ex) { if (!RaiseFaultHandlers(ex)) - throw ex; + throw; } finally { @@ -420,19 +420,28 @@ protected override List RunWithReturn(bool success) RaiseOnStart, () => { - if (outputProcessor != null) - result = outputProcessor.Result; - if (result == null) - result = new List(); - - RaiseOnEnd(result); - - if (Errors != null) + try { - OnErrorData?.Invoke(Errors); - thrownException = thrownException ?? new ProcessException(this); - if (!RaiseFaultHandlers(thrownException)) + if (outputProcessor != null) + result = outputProcessor.Result; + if (result == null) + result = new List(); + + if (Errors != null) + { + OnErrorData?.Invoke(Errors); + thrownException = thrownException ?? new ProcessException(this); throw thrownException; + } + } + catch (Exception ex) + { + if (!RaiseFaultHandlers(ex)) + throw; + } + finally + { + RaiseOnEnd(result); } }, (ex, error) => From f09a6687594c2440f9ca284573f407b5e0bf0722 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 5 Mar 2018 18:12:27 -0500 Subject: [PATCH 0229/1008] Completed functionality to use octorun js --- octorun/bin/octorun | 2 - octorun/src/authentication.js | 176 ++++++------------ octorun/src/bin/app-login.js | 122 ++++++++++-- octorun/src/bin/app-usage.js | 77 +++++--- src/GitHub.Api/Authentication/LoginManager.cs | 87 ++++----- 5 files changed, 246 insertions(+), 218 deletions(-) diff --git a/octorun/bin/octorun b/octorun/bin/octorun index 9c031d64f..b6623d43e 100644 --- a/octorun/bin/octorun +++ b/octorun/bin/octorun @@ -1,5 +1,3 @@ #!/usr/bin/env node -process.stdout.write("node:", process.argv[0]); - require('../src/bin/app.js'); diff --git a/octorun/src/authentication.js b/octorun/src/authentication.js index a8cdda693..ab851c01f 100644 --- a/octorun/src/authentication.js +++ b/octorun/src/authentication.js @@ -1,136 +1,66 @@ +var endOfLine = require('os').EOL; var config = require("./configuration"); var octokitWrapper = require("./octokit"); var scopes = ["user", "repo", "gist", "write:public_key"]; -var stdIn = process.openStdin(); - -var awaiter = null; - -stdIn.addListener("data", function (d) { - var content = d.toString().trim(); - - if (awaiter) { - var _awaiter = awaiter; - awaiter = null; - _awaiter(content); - } -}); - -var handleBasicAuthentication = function (onSuccess, onRequiresTwoFa, onFailure) { - var username = null; - var password = null; - - var withPassword = function (input) { - password = input; - - var octokit = octokitWrapper.createOctokit(); - - octokit.authenticate({ - type: "basic", - username: username, - password: password - }); - - octokit.authorization.create({ - scopes: scopes, - note: config.appName, - client_id: config.clientId, - client_secret: config.clientSecret - }, function (err, res) { - if (err) { - if (err.message === '{"message":"Must specify two-factor authentication OTP code.","documentation_url":"https://developer.github.com/v3/auth#working-with-two-factor-authentication"}') { - onRequiresTwoFa(); - return; - } - else { - onFailure(err) - } +var lockedRegex = new RegExp("number of login attempts exceeded", "gi"); +var twoFactorRegex = new RegExp("must specify two-factor authentication OTP code", "gi"); + +var handleBasicAuthentication = function (username, password, onSuccess, onRequiresTwoFa, onLocked, onFailure) { + var octokit = octokitWrapper.createOctokit(); + + octokit.authenticate({ + type: "basic", + username: username, + password: password + }); + + octokit.authorization.create({ + scopes: scopes, + note: config.appName, + client_id: config.clientId, + client_secret: config.clientSecret + }, function (err, res) { + if (err) { + if (twoFactorRegex.test(err.message)) { + onRequiresTwoFa(); } else { - onSuccess(res.data.token); - } - }); - } - - var promptPassword = function () { - process.stdout.write("Password: "); - awaiter = withPassword; - } - - var withUser = function (input) { - username = input; - promptPassword(); - } - - var promptUser = function () { - process.stdout.write("Username: "); - awaiter = withUser; - } - - promptUser(); -} - -var handleTwoFactorAuthentication = function (onSuccess, onFailure) { - var username = null; - var password = null; - var twoFactor = null; - - var withTwoFactor = function (input) { - twoFactor = input; - - var octokit = octokitWrapper.createOctokit(); - - octokit.authenticate({ - type: "basic", - username: username, - password: password - }); - - octokit.authorization.create({ - scopes: scopes, - note: config.appName, - client_id: config.clientId, - client_secret: config.clientSecret, - headers: { - "X-GitHub-OTP": twoFactor - } - }, function (err, res) { - if (err) { onFailure(err) } - else { - onSuccess(res.data.token); - } - }); - } - - var promptTwoFactor = function () { - process.stdout.write("Two Factor: "); - awaiter = withTwoFactor; - } - - var withPassword = function (input) { - password = input; - promptTwoFactor(); - } - - var promptPassword = function () { - process.stdout.write("Password: "); - awaiter = withPassword; - } - - var withUser = function (input) { - username = input; - promptPassword(); - } - - var promptUser = function () { - process.stdout.write("Username: "); - awaiter = withUser; - } + } + else { + onSuccess(res.data.token); + } + }); +} - promptUser(); +var handleTwoFactorAuthentication = function (username, password, twoFactor, onSuccess, onLocked, onFailure) { + var octokit = octokitWrapper.createOctokit(); + + octokit.authenticate({ + type: "basic", + username: username, + password: password + }); + + octokit.authorization.create({ + scopes: scopes, + note: config.appName, + client_id: config.clientId, + client_secret: config.clientSecret, + headers: { + "X-GitHub-OTP": twoFactor + } + }, function (err, res) { + if (err) { + onFailure(err) + } + else { + onSuccess(res.data.token); + } + }); } module.exports = { diff --git a/octorun/src/bin/app-login.js b/octorun/src/bin/app-login.js index f90504f25..b763e3957 100644 --- a/octorun/src/bin/app-login.js +++ b/octorun/src/bin/app-login.js @@ -2,29 +2,117 @@ var commander = require("commander"); var package = require('../../package.json') var authentication = require('../authentication') +var endOfLine = require('os').EOL; + commander .version(package.version) .option('-t, --twoFactor') .parse(process.argv); +var encoding = 'utf-8'; + if (commander.twoFactor) { - authentication.handleTwoFactorAuthentication(function (token) { - process.stdout.write(token); - process.exit(); - }, function (err) { - process.stdout.write(err); - process.exit(); - }); + var handleTwoFactorAuthentication = function (username, password, token) { + authentication.handleTwoFactorAuthentication(username, password, token, function (token) { + process.stdout.write(token); + process.stdout.write(endOfLine); + process.exit(); + }, function () { + process.stdout.write("Account locked."); + process.stdout.write(endOfLine); + process.exit(); + }, function (err) { + process.stdout.write("Error"); + process.stdout.write(endOfLine); + process.stdout.write(err); + process.stdout.write(endOfLine); + process.exit(); + }); + } + + if (process.stdin.isTTY) { + var readlineSync = require("readline-sync"); + var username = readlineSync.question('User: '); + var password = readlineSync.question('Password: ', { + hideEchoBack: true + }); + + var twoFactor = readlineSync.question('Two Factor: '); + + handleTwoFactorAuthentication(username, password, twoFactor); + } + else { + var data = ''; + process.stdin.setEncoding(encoding); + + process.stdin.on('readable', function () { + var chunk; + while (chunk = process.stdin.read()) { + data += chunk; + } + }); + + process.stdin.on('end', function () { + var items = data.toString() + .split(/\r?\n/) + .filter(function (item) { return item; }); + + handleTwoFactorAuthentication(items[0], items[1], items[2]); + }); + } } else { - authentication.handleBasicAuthentication(function (token) { - process.stdout.write(token); - process.exit(); - }, function () { - process.stdout.write("Must specify two-factor authentication OTP code."); - process.exit(); - }, function (err) { - process.stdout.write(err); - process.exit(); - }); + + var handleTwoFactorAuthentication = function (username, password) { + authentication.handleBasicAuthentication(username, password, + function (token) { + process.stdout.write(token); + process.stdout.write(endOfLine); + process.exit(); + }, function () { + process.stdout.write("Must specify two-factor authentication OTP code."); + process.stdout.write(endOfLine); + process.exit(); + }, function () { + process.stdout.write("Account locked."); + process.stdout.write(endOfLine); + process.exit(); + }, function (err) { + process.stdout.write("Error"); + process.stdout.write(endOfLine); + process.stdout.write(err); + process.stdout.write(endOfLine); + process.exit(); + }); + } + + if (process.stdin.isTTY) { + var readlineSync = require("readline-sync"); + + var username = readlineSync.question('User: '); + var password = readlineSync.question('Password: ', { + hideEchoBack: true + }); + + handleTwoFactorAuthentication(username, password); + } + else { + var data = ''; + process.stdin.setEncoding(encoding); + + process.stdin.on('readable', function () { + var chunk; + while (chunk = process.stdin.read()) { + data += chunk; + } + }); + + process.stdin.on('end', function () { + var items = data.toString() + .split(/\r?\n/) + .filter(function (item) { return item; }); + + handleTwoFactorAuthentication(items[0], items[1]); + }); + } } \ No newline at end of file diff --git a/octorun/src/bin/app-usage.js b/octorun/src/bin/app-usage.js index a6279e411..6a00d2772 100644 --- a/octorun/src/bin/app-usage.js +++ b/octorun/src/bin/app-usage.js @@ -1,42 +1,67 @@ var commander = require("commander"); var package = require('../../package.json') -var readlineSync = require("readline-sync"); var endOfLine = require('os').EOL; commander .version(package.version) .parse(process.argv); -var postData = readlineSync.question(); +var processData = function (postData) { + var https = require('https'); -var https = require('https'); + var options = { + hostname: 'central.github.com', + path: '/api/usage/unity', + method: 'POST', + headers: { + 'Content-Type': 'application/json' + } + }; -var options = { - hostname: 'central.github.com', - path: '/api/usage/unity', - method: 'POST', - headers: { - 'Content-Type': 'application/json' - } -}; + var req = https.request(options, function (res) { + process.stdout.write('statusCode:', res.statusCode); -var req = https.request(options, function (res) { - process.stdout.write('statusCode:', res.statusCode); + res.on('data', function (d) { + process.stdout.write(d); + process.stdout.write(endOfLine); + }); - res.on('data', function (d) { - process.stdout.write(d); - process.stdout.write(endOfLine); + res.on('end', function (d) { + process.exit(); + }); }); - - res.on('end', function (d) { - process.exit(); + + req.on('error', function (e) { + console.error(e); + process.exit(-1); }); -}); -req.on('error', function (e) { - console.error(e); - process.exit(-1); -}); + req.write(postData); + req.end(); +} + +if (process.stdin.isTTY) { + var readlineSync = require("readline-sync"); + var postData = readlineSync.question(); -req.write(postData); -req.end(); \ No newline at end of file + processData(postData); +} +else { + var data = ''; + process.stdin.setEncoding(encoding); + + process.stdin.on('readable', function () { + var chunk; + while (chunk = process.stdin.read()) { + data += chunk; + } + }); + + process.stdin.on('end', function () { + var items = data.toString() + .split(/\r?\n/) + .filter(function (item) { return item; }); + + processData(items[0]); + }); +} \ No newline at end of file diff --git a/src/GitHub.Api/Authentication/LoginManager.cs b/src/GitHub.Api/Authentication/LoginManager.cs index ffed03457..e1fead259 100644 --- a/src/GitHub.Api/Authentication/LoginManager.cs +++ b/src/GitHub.Api/Authentication/LoginManager.cs @@ -263,7 +263,7 @@ string password ApplicationAuthorization auth = null; var loginTask = new SimpleListProcessTask(taskManager.Token, nodeJsExecutablePath, $"{octorunScript} login"); - loginTask.Configure(processManager, workingDirectory: octorunScript.Parent.Parent.Parent, withInput: true); + loginTask.Configure(processManager, workingDirectory: octorunScript.Parent.Parent, withInput: true); loginTask.OnStartProcess += proc => { proc.StandardInput.WriteLine(username); @@ -271,45 +271,35 @@ string password proc.StandardInput.Close(); }; - loginTask.OnEndProcess += proc => { - logger.Trace("Exit Code: ", proc.Process.ExitCode); - }; + var ret = (await loginTask.StartAwait()); - var ret = (await loginTask.StartAwait()).ToArray(); + if (ret.Count == 0) + { + throw new Exception("Authentication failed"); + } - for (var index = 0; index < ret.Length; index++) + if (ret.Count == 1) { - var result = ret[index]; - logger.Trace("line {0}: {1}", index, result); + if (ret[0] == ("Must specify two-factor authentication OTP code.")) + { + keychain.SetToken(host, ret[0]); + await keychain.Save(host); + throw new TwoFactorRequiredException(TwoFactorType.Unknown); + } + + if (ret[0] == "Account locked.") + { + throw new LoginAttemptsExceededException(null, null); + } + + auth = new ApplicationAuthorization(ret[0]); + } + else + { + throw new Exception("Authentication failed"); } - throw new Exception("Authentication failed"); - - // if (ret.Count == 0) - // { - // throw new Exception("Authentication failed"); - // } - // // success - // else if (ret.Count == 1) - // { - // auth = new ApplicationAuthorization(ret[0]); - // } - // else - // { - // if (ret[0] == "Must specify two-factor authentication OTP code.") - // { - // keychain.SetToken(host, ret[1]); - // await keychain.Save(host); - // throw new TwoFactorRequiredException(TwoFactorType.Unknown); - // } - // else if (ret[0] == "locked") - // { - // throw new LoginAttemptsExceededException(null, null); - // } - // else - // throw new Exception("Authentication failed"); - // } - // return auth; + return auth; } private async Task TryContinueLogin( @@ -324,7 +314,7 @@ string code ApplicationAuthorization auth = null; var loginTask = new SimpleListProcessTask(taskManager.Token, nodeJsExecutablePath, $"{octorunScript} login --twoFactor"); - loginTask.Configure(processManager, workingDirectory: nodeJsExecutablePath.Parent, withInput: true); + loginTask.Configure(processManager, workingDirectory: octorunScript.Parent.Parent, withInput: true); loginTask.OnStartProcess += proc => { proc.StandardInput.WriteLine(username); @@ -332,31 +322,28 @@ string code proc.StandardInput.WriteLine(code); proc.StandardInput.Close(); }; - var ret = await loginTask.StartAwait(); + + var ret = (await loginTask.StartAwait()); if (ret.Count == 0) { throw new Exception("Authentication failed"); } + // success - else if (ret.Count == 1) + if (ret.Count == 1) { + if (ret[0] == "Account locked.") + { + throw new LoginAttemptsExceededException(null, null); + } + auth = new ApplicationAuthorization(ret[0]); } else { - if (ret[0] == "2fa") - { - keychain.SetToken(host, ret[1]); - await keychain.Save(host); - throw new TwoFactorRequiredException(TwoFactorType.Unknown); - } - else if (ret[0] == "locked") - { - throw new LoginAttemptsExceededException(null, null); - } - else - throw new Exception("Authentication failed"); + throw new Exception("Authentication failed"); } + return auth; } From ff6511541ab857fc292d2cb141e818b03557aeb5 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Mon, 5 Mar 2018 18:13:10 -0500 Subject: [PATCH 0230/1008] Adding node_modules for safe keeping --- octorun/.gitignore | 1 - octorun/node_modules/commander/CHANGELOG.md | 350 + octorun/node_modules/commander/LICENSE | 22 + octorun/node_modules/commander/Readme.md | 408 + octorun/node_modules/commander/index.js | 1157 + octorun/node_modules/commander/package.json | 114 + .../node_modules/commander/typings/index.d.ts | 309 + octorun/node_modules/dotenv/.editorconfig | 13 + octorun/node_modules/dotenv/.npmignore | 12 + octorun/node_modules/dotenv/.travis.yml | 6 + octorun/node_modules/dotenv/Contributing.md | 25 + octorun/node_modules/dotenv/README.md | 198 + octorun/node_modules/dotenv/config.js | 11 + octorun/node_modules/dotenv/dotenv.png | 3 + octorun/node_modules/dotenv/lib/main.js | 92 + octorun/node_modules/dotenv/package.json | 94 + octorun/node_modules/dotenv/test/config.js | 38 + octorun/node_modules/dotenv/test/main.js | 204 + .../octokit-rest-for-node-v0.12/.travis.yml | 16 + .../octokit-rest-for-node-v0.12/LICENSE.md | 21 + .../octokit-rest-for-node-v0.12/README.md | 31 + .../octokit-rest-for-node-v0.12/build.js | 30518 ++++++++++++++++ .../octokit-rest-for-node-v0.12/index.js | 8 + .../octokit-rest-for-node-v0.12/package.json | 102 + .../octokit-rest-for-node-v0.12/test.js | 35 + 25 files changed, 33787 insertions(+), 1 deletion(-) create mode 100644 octorun/node_modules/commander/CHANGELOG.md create mode 100644 octorun/node_modules/commander/LICENSE create mode 100644 octorun/node_modules/commander/Readme.md create mode 100644 octorun/node_modules/commander/index.js create mode 100644 octorun/node_modules/commander/package.json create mode 100644 octorun/node_modules/commander/typings/index.d.ts create mode 100644 octorun/node_modules/dotenv/.editorconfig create mode 100644 octorun/node_modules/dotenv/.npmignore create mode 100644 octorun/node_modules/dotenv/.travis.yml create mode 100644 octorun/node_modules/dotenv/Contributing.md create mode 100644 octorun/node_modules/dotenv/README.md create mode 100644 octorun/node_modules/dotenv/config.js create mode 100644 octorun/node_modules/dotenv/dotenv.png create mode 100644 octorun/node_modules/dotenv/lib/main.js create mode 100644 octorun/node_modules/dotenv/package.json create mode 100644 octorun/node_modules/dotenv/test/config.js create mode 100644 octorun/node_modules/dotenv/test/main.js create mode 100644 octorun/node_modules/octokit-rest-for-node-v0.12/.travis.yml create mode 100644 octorun/node_modules/octokit-rest-for-node-v0.12/LICENSE.md create mode 100644 octorun/node_modules/octokit-rest-for-node-v0.12/README.md create mode 100644 octorun/node_modules/octokit-rest-for-node-v0.12/build.js create mode 100644 octorun/node_modules/octokit-rest-for-node-v0.12/index.js create mode 100644 octorun/node_modules/octokit-rest-for-node-v0.12/package.json create mode 100644 octorun/node_modules/octokit-rest-for-node-v0.12/test.js diff --git a/octorun/.gitignore b/octorun/.gitignore index ef4fcce9d..0319b67e3 100644 --- a/octorun/.gitignore +++ b/octorun/.gitignore @@ -1,3 +1,2 @@ .env -node_modules npm-debug.log diff --git a/octorun/node_modules/commander/CHANGELOG.md b/octorun/node_modules/commander/CHANGELOG.md new file mode 100644 index 000000000..29f0707c6 --- /dev/null +++ b/octorun/node_modules/commander/CHANGELOG.md @@ -0,0 +1,350 @@ + +2.14.1 / 2018-02-07 +================== + + * Fix typing of help function + +2.14.0 / 2018-02-05 +================== + + * only register the option:version event once + * Fixes issue #727: Passing empty string for option on command is set to undefined + * enable eqeqeq rule + * resolves #754 add linter configuration to project + * resolves #560 respect custom name for version option + * document how to override the version flag + * document using options per command + +2.13.0 / 2018-01-09 +================== + + * Do not print default for --no- + * remove trailing spaces in command help + * Update CI's Node.js to LTS and latest version + * typedefs: Command and Option types added to commander namespace + +2.12.2 / 2017-11-28 +================== + + * fix: typings are not shipped + +2.12.1 / 2017-11-23 +================== + + * Move @types/node to dev dependency + +2.12.0 / 2017-11-22 +================== + + * add attributeName() method to Option objects + * Documentation updated for options with --no prefix + * typings: `outputHelp` takes a string as the first parameter + * typings: use overloads + * feat(typings): update to match js api + * Print default value in option help + * Fix translation error + * Fail when using same command and alias (#491) + * feat(typings): add help callback + * fix bug when description is add after command with options (#662) + * Format js code + * Rename History.md to CHANGELOG.md (#668) + * feat(typings): add typings to support TypeScript (#646) + * use current node + +2.11.0 / 2017-07-03 +================== + + * Fix help section order and padding (#652) + * feature: support for signals to subcommands (#632) + * Fixed #37, --help should not display first (#447) + * Fix translation errors. (#570) + * Add package-lock.json + * Remove engines + * Upgrade package version + * Prefix events to prevent conflicts between commands and options (#494) + * Removing dependency on graceful-readlink + * Support setting name in #name function and make it chainable + * Add .vscode directory to .gitignore (Visual Studio Code metadata) + * Updated link to ruby commander in readme files + +2.10.0 / 2017-06-19 +================== + + * Update .travis.yml. drop support for older node.js versions. + * Fix require arguments in README.md + * On SemVer you do not start from 0.0.1 + * Add missing semi colon in readme + * Add save param to npm install + * node v6 travis test + * Update Readme_zh-CN.md + * Allow literal '--' to be passed-through as an argument + * Test subcommand alias help + * link build badge to master branch + * Support the alias of Git style sub-command + * added keyword commander for better search result on npm + * Fix Sub-Subcommands + * test node.js stable + * Fixes TypeError when a command has an option called `--description` + * Update README.md to make it beginner friendly and elaborate on the difference between angled and square brackets. + * Add chinese Readme file + +2.9.0 / 2015-10-13 +================== + + * Add option `isDefault` to set default subcommand #415 @Qix- + * Add callback to allow filtering or post-processing of help text #434 @djulien + * Fix `undefined` text in help information close #414 #416 @zhiyelee + +2.8.1 / 2015-04-22 +================== + + * Back out `support multiline description` Close #396 #397 + +2.8.0 / 2015-04-07 +================== + + * Add `process.execArg` support, execution args like `--harmony` will be passed to sub-commands #387 @DigitalIO @zhiyelee + * Fix bug in Git-style sub-commands #372 @zhiyelee + * Allow commands to be hidden from help #383 @tonylukasavage + * When git-style sub-commands are in use, yet none are called, display help #382 @claylo + * Add ability to specify arguments syntax for top-level command #258 @rrthomas + * Support multiline descriptions #208 @zxqfox + +2.7.1 / 2015-03-11 +================== + + * Revert #347 (fix collisions when option and first arg have same name) which causes a bug in #367. + +2.7.0 / 2015-03-09 +================== + + * Fix git-style bug when installed globally. Close #335 #349 @zhiyelee + * Fix collisions when option and first arg have same name. Close #346 #347 @tonylukasavage + * Add support for camelCase on `opts()`. Close #353 @nkzawa + * Add node.js 0.12 and io.js to travis.yml + * Allow RegEx options. #337 @palanik + * Fixes exit code when sub-command failing. Close #260 #332 @pirelenito + * git-style `bin` files in $PATH make sense. Close #196 #327 @zhiyelee + +2.6.0 / 2014-12-30 +================== + + * added `Command#allowUnknownOption` method. Close #138 #318 @doozr @zhiyelee + * Add application description to the help msg. Close #112 @dalssoft + +2.5.1 / 2014-12-15 +================== + + * fixed two bugs incurred by variadic arguments. Close #291 @Quentin01 #302 @zhiyelee + +2.5.0 / 2014-10-24 +================== + + * add support for variadic arguments. Closes #277 @whitlockjc + +2.4.0 / 2014-10-17 +================== + + * fixed a bug on executing the coercion function of subcommands option. Closes #270 + * added `Command.prototype.name` to retrieve command name. Closes #264 #266 @tonylukasavage + * added `Command.prototype.opts` to retrieve all the options as a simple object of key-value pairs. Closes #262 @tonylukasavage + * fixed a bug on subcommand name. Closes #248 @jonathandelgado + * fixed function normalize doesn’t honor option terminator. Closes #216 @abbr + +2.3.0 / 2014-07-16 +================== + + * add command alias'. Closes PR #210 + * fix: Typos. Closes #99 + * fix: Unused fs module. Closes #217 + +2.2.0 / 2014-03-29 +================== + + * add passing of previous option value + * fix: support subcommands on windows. Closes #142 + * Now the defaultValue passed as the second argument of the coercion function. + +2.1.0 / 2013-11-21 +================== + + * add: allow cflag style option params, unit test, fixes #174 + +2.0.0 / 2013-07-18 +================== + + * remove input methods (.prompt, .confirm, etc) + +1.3.2 / 2013-07-18 +================== + + * add support for sub-commands to co-exist with the original command + +1.3.1 / 2013-07-18 +================== + + * add quick .runningCommand hack so you can opt-out of other logic when running a sub command + +1.3.0 / 2013-07-09 +================== + + * add EACCES error handling + * fix sub-command --help + +1.2.0 / 2013-06-13 +================== + + * allow "-" hyphen as an option argument + * support for RegExp coercion + +1.1.1 / 2012-11-20 +================== + + * add more sub-command padding + * fix .usage() when args are present. Closes #106 + +1.1.0 / 2012-11-16 +================== + + * add git-style executable subcommand support. Closes #94 + +1.0.5 / 2012-10-09 +================== + + * fix `--name` clobbering. Closes #92 + * fix examples/help. Closes #89 + +1.0.4 / 2012-09-03 +================== + + * add `outputHelp()` method. + +1.0.3 / 2012-08-30 +================== + + * remove invalid .version() defaulting + +1.0.2 / 2012-08-24 +================== + + * add `--foo=bar` support [arv] + * fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus] + +1.0.1 / 2012-08-03 +================== + + * fix issue #56 + * fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode()) + +1.0.0 / 2012-07-05 +================== + + * add support for optional option descriptions + * add defaulting of `.version()` to package.json's version + +0.6.1 / 2012-06-01 +================== + + * Added: append (yes or no) on confirmation + * Added: allow node.js v0.7.x + +0.6.0 / 2012-04-10 +================== + + * Added `.prompt(obj, callback)` support. Closes #49 + * Added default support to .choose(). Closes #41 + * Fixed the choice example + +0.5.1 / 2011-12-20 +================== + + * Fixed `password()` for recent nodes. Closes #36 + +0.5.0 / 2011-12-04 +================== + + * Added sub-command option support [itay] + +0.4.3 / 2011-12-04 +================== + + * Fixed custom help ordering. Closes #32 + +0.4.2 / 2011-11-24 +================== + + * Added travis support + * Fixed: line-buffered input automatically trimmed. Closes #31 + +0.4.1 / 2011-11-18 +================== + + * Removed listening for "close" on --help + +0.4.0 / 2011-11-15 +================== + + * Added support for `--`. Closes #24 + +0.3.3 / 2011-11-14 +================== + + * Fixed: wait for close event when writing help info [Jerry Hamlet] + +0.3.2 / 2011-11-01 +================== + + * Fixed long flag definitions with values [felixge] + +0.3.1 / 2011-10-31 +================== + + * Changed `--version` short flag to `-V` from `-v` + * Changed `.version()` so it's configurable [felixge] + +0.3.0 / 2011-10-31 +================== + + * Added support for long flags only. Closes #18 + +0.2.1 / 2011-10-24 +================== + + * "node": ">= 0.4.x < 0.7.0". Closes #20 + +0.2.0 / 2011-09-26 +================== + + * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs] + +0.1.0 / 2011-08-24 +================== + + * Added support for custom `--help` output + +0.0.5 / 2011-08-18 +================== + + * Changed: when the user enters nothing prompt for password again + * Fixed issue with passwords beginning with numbers [NuckChorris] + +0.0.4 / 2011-08-15 +================== + + * Fixed `Commander#args` + +0.0.3 / 2011-08-15 +================== + + * Added default option value support + +0.0.2 / 2011-08-15 +================== + + * Added mask support to `Command#password(str[, mask], fn)` + * Added `Command#password(str, fn)` + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/octorun/node_modules/commander/LICENSE b/octorun/node_modules/commander/LICENSE new file mode 100644 index 000000000..10f997ab1 --- /dev/null +++ b/octorun/node_modules/commander/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2011 TJ Holowaychuk + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/octorun/node_modules/commander/Readme.md b/octorun/node_modules/commander/Readme.md new file mode 100644 index 000000000..6a21b9009 --- /dev/null +++ b/octorun/node_modules/commander/Readme.md @@ -0,0 +1,408 @@ +# Commander.js + + +[![Build Status](https://api.travis-ci.org/tj/commander.js.svg?branch=master)](http://travis-ci.org/tj/commander.js) +[![NPM Version](http://img.shields.io/npm/v/commander.svg?style=flat)](https://www.npmjs.org/package/commander) +[![NPM Downloads](https://img.shields.io/npm/dm/commander.svg?style=flat)](https://www.npmjs.org/package/commander) +[![Join the chat at https://gitter.im/tj/commander.js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/tj/commander.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + + The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/commander-rb/commander). + [API documentation](http://tj.github.com/commander.js/) + + +## Installation + + $ npm install commander --save + +## Option parsing + +Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('commander'); + +program + .version('0.1.0') + .option('-p, --peppers', 'Add peppers') + .option('-P, --pineapple', 'Add pineapple') + .option('-b, --bbq-sauce', 'Add bbq sauce') + .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble') + .parse(process.argv); + +console.log('you ordered a pizza with:'); +if (program.peppers) console.log(' - peppers'); +if (program.pineapple) console.log(' - pineapple'); +if (program.bbqSauce) console.log(' - bbq'); +console.log(' - %s cheese', program.cheese); +``` + +Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc. + +Note that multi-word options starting with `--no` prefix negate the boolean value of the following word. For example, `--no-sauce` sets the value of `program.sauce` to false. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('commander'); + +program + .option('--no-sauce', 'Remove sauce') + .parse(process.argv); + +console.log('you ordered a pizza'); +if (program.sauce) console.log(' with sauce'); +else console.log(' without sauce'); +``` + +## Version option + +Calling the `version` implicitly adds the `-V` and `--version` options to the command. +When either of these options is present, the command prints the version number and exits. + + $ ./examples/pizza -V + 0.0.1 + +If you want your program to respond to the `-v` option instead of the `-V` option, simply pass custom flags to the `version` method using the same syntax as the `option` method. + +```js +program + .version('0.0.1', '-v, --version') +``` + +The version flags can be named anything, but the long option is required. + +## Command-specific options + +You can attach options to a command. + +```js +#!/usr/bin/env node + +var program = require('commander'); + +program + .command('rm ') + .option('-r, --recursive', 'Remove recursively') + .action(function (dir, cmd) { + console.log('remove ' + dir + (cmd.recursive ? ' recursively' : '')) + }) + +program.parse(process.argv) +``` + +A command's options are validated when the command is used. Any unknown options will be reported as an error. However, if an action-based command does not define an action, then the options are not validated. + +## Coercion + +```js +function range(val) { + return val.split('..').map(Number); +} + +function list(val) { + return val.split(','); +} + +function collect(val, memo) { + memo.push(val); + return memo; +} + +function increaseVerbosity(v, total) { + return total + 1; +} + +program + .version('0.1.0') + .usage('[options] ') + .option('-i, --integer ', 'An integer argument', parseInt) + .option('-f, --float ', 'A float argument', parseFloat) + .option('-r, --range ..', 'A range', range) + .option('-l, --list ', 'A list', list) + .option('-o, --optional [value]', 'An optional value') + .option('-c, --collect [value]', 'A repeatable value', collect, []) + .option('-v, --verbose', 'A value that can be increased', increaseVerbosity, 0) + .parse(process.argv); + +console.log(' int: %j', program.integer); +console.log(' float: %j', program.float); +console.log(' optional: %j', program.optional); +program.range = program.range || []; +console.log(' range: %j..%j', program.range[0], program.range[1]); +console.log(' list: %j', program.list); +console.log(' collect: %j', program.collect); +console.log(' verbosity: %j', program.verbose); +console.log(' args: %j', program.args); +``` + +## Regular Expression +```js +program + .version('0.1.0') + .option('-s --size ', 'Pizza size', /^(large|medium|small)$/i, 'medium') + .option('-d --drink [drink]', 'Drink', /^(coke|pepsi|izze)$/i) + .parse(process.argv); + +console.log(' size: %j', program.size); +console.log(' drink: %j', program.drink); +``` + +## Variadic arguments + + The last argument of a command can be variadic, and only the last argument. To make an argument variadic you have to + append `...` to the argument name. Here is an example: + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('commander'); + +program + .version('0.1.0') + .command('rmdir [otherDirs...]') + .action(function (dir, otherDirs) { + console.log('rmdir %s', dir); + if (otherDirs) { + otherDirs.forEach(function (oDir) { + console.log('rmdir %s', oDir); + }); + } + }); + +program.parse(process.argv); +``` + + An `Array` is used for the value of a variadic argument. This applies to `program.args` as well as the argument passed + to your action as demonstrated above. + +## Specify the argument syntax + +```js +#!/usr/bin/env node + +var program = require('commander'); + +program + .version('0.1.0') + .arguments(' [env]') + .action(function (cmd, env) { + cmdValue = cmd; + envValue = env; + }); + +program.parse(process.argv); + +if (typeof cmdValue === 'undefined') { + console.error('no command given!'); + process.exit(1); +} +console.log('command:', cmdValue); +console.log('environment:', envValue || "no environment given"); +``` +Angled brackets (e.g. ``) indicate required input. Square brackets (e.g. `[env]`) indicate optional input. + +## Git-style sub-commands + +```js +// file: ./examples/pm +var program = require('commander'); + +program + .version('0.1.0') + .command('install [name]', 'install one or more packages') + .command('search [query]', 'search with optional query') + .command('list', 'list packages installed', {isDefault: true}) + .parse(process.argv); +``` + +When `.command()` is invoked with a description argument, no `.action(callback)` should be called to handle sub-commands, otherwise there will be an error. This tells commander that you're going to use separate executables for sub-commands, much like `git(1)` and other popular tools. +The commander will try to search the executables in the directory of the entry script (like `./examples/pm`) with the name `program-command`, like `pm-install`, `pm-search`. + +Options can be passed with the call to `.command()`. Specifying `true` for `opts.noHelp` will remove the option from the generated help output. Specifying `true` for `opts.isDefault` will run the subcommand if no other subcommand is specified. + +If the program is designed to be installed globally, make sure the executables have proper modes, like `755`. + +### `--harmony` + +You can enable `--harmony` option in two ways: +* Use `#! /usr/bin/env node --harmony` in the sub-commands scripts. Note some os version don’t support this pattern. +* Use the `--harmony` option when call the command, like `node --harmony examples/pm publish`. The `--harmony` option will be preserved when spawning sub-command process. + +## Automated --help + + The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free: + +``` + $ ./examples/pizza --help + + Usage: pizza [options] + + An application for pizzas ordering + + Options: + + -h, --help output usage information + -V, --version output the version number + -p, --peppers Add peppers + -P, --pineapple Add pineapple + -b, --bbq Add bbq sauce + -c, --cheese Add the specified type of cheese [marble] + -C, --no-cheese You do not want any cheese + +``` + +## Custom help + + You can display arbitrary `-h, --help` information + by listening for "--help". Commander will automatically + exit once you are done so that the remainder of your program + does not execute causing undesired behaviours, for example + in the following executable "stuff" will not output when + `--help` is used. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('commander'); + +program + .version('0.1.0') + .option('-f, --foo', 'enable some foo') + .option('-b, --bar', 'enable some bar') + .option('-B, --baz', 'enable some baz'); + +// must be before .parse() since +// node's emit() is immediate + +program.on('--help', function(){ + console.log(' Examples:'); + console.log(''); + console.log(' $ custom-help --help'); + console.log(' $ custom-help -h'); + console.log(''); +}); + +program.parse(process.argv); + +console.log('stuff'); +``` + +Yields the following help output when `node script-name.js -h` or `node script-name.js --help` are run: + +``` + +Usage: custom-help [options] + +Options: + + -h, --help output usage information + -V, --version output the version number + -f, --foo enable some foo + -b, --bar enable some bar + -B, --baz enable some baz + +Examples: + + $ custom-help --help + $ custom-help -h + +``` + +## .outputHelp(cb) + +Output help information without exiting. +Optional callback cb allows post-processing of help text before it is displayed. + +If you want to display help by default (e.g. if no command was provided), you can use something like: + +```js +var program = require('commander'); +var colors = require('colors'); + +program + .version('0.1.0') + .command('getstream [url]', 'get stream URL') + .parse(process.argv); + +if (!process.argv.slice(2).length) { + program.outputHelp(make_red); +} + +function make_red(txt) { + return colors.red(txt); //display the help text in red on the console +} +``` + +## .help(cb) + + Output help information and exit immediately. + Optional callback cb allows post-processing of help text before it is displayed. + +## Examples + +```js +var program = require('commander'); + +program + .version('0.1.0') + .option('-C, --chdir ', 'change the working directory') + .option('-c, --config ', 'set config path. defaults to ./deploy.conf') + .option('-T, --no-tests', 'ignore test hook'); + +program + .command('setup [env]') + .description('run setup commands for all envs') + .option("-s, --setup_mode [mode]", "Which setup mode to use") + .action(function(env, options){ + var mode = options.setup_mode || "normal"; + env = env || 'all'; + console.log('setup for %s env(s) with %s mode', env, mode); + }); + +program + .command('exec ') + .alias('ex') + .description('execute the given remote cmd') + .option("-e, --exec_mode ", "Which exec mode to use") + .action(function(cmd, options){ + console.log('exec "%s" using %s mode', cmd, options.exec_mode); + }).on('--help', function() { + console.log(' Examples:'); + console.log(); + console.log(' $ deploy exec sequential'); + console.log(' $ deploy exec async'); + console.log(); + }); + +program + .command('*') + .action(function(env){ + console.log('deploying "%s"', env); + }); + +program.parse(process.argv); +``` + +More Demos can be found in the [examples](https://github.com/tj/commander.js/tree/master/examples) directory. + +## License + +MIT diff --git a/octorun/node_modules/commander/index.js b/octorun/node_modules/commander/index.js new file mode 100644 index 000000000..c467b10f7 --- /dev/null +++ b/octorun/node_modules/commander/index.js @@ -0,0 +1,1157 @@ +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter; +var spawn = require('child_process').spawn; +var path = require('path'); +var dirname = path.dirname; +var basename = path.basename; +var fs = require('fs'); + +/** + * Inherit `Command` from `EventEmitter.prototype`. + */ + +require('util').inherits(Command, EventEmitter); + +/** + * Expose the root command. + */ + +exports = module.exports = new Command(); + +/** + * Expose `Command`. + */ + +exports.Command = Command; + +/** + * Expose `Option`. + */ + +exports.Option = Option; + +/** + * Initialize a new `Option` with the given `flags` and `description`. + * + * @param {String} flags + * @param {String} description + * @api public + */ + +function Option(flags, description) { + this.flags = flags; + this.required = ~flags.indexOf('<'); + this.optional = ~flags.indexOf('['); + this.bool = !~flags.indexOf('-no-'); + flags = flags.split(/[ ,|]+/); + if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift(); + this.long = flags.shift(); + this.description = description || ''; +} + +/** + * Return option name. + * + * @return {String} + * @api private + */ + +Option.prototype.name = function() { + return this.long + .replace('--', '') + .replace('no-', ''); +}; + +/** + * Return option name, in a camelcase format that can be used + * as a object attribute key. + * + * @return {String} + * @api private + */ + +Option.prototype.attributeName = function() { + return camelcase(this.name()); +}; + +/** + * Check if `arg` matches the short or long flag. + * + * @param {String} arg + * @return {Boolean} + * @api private + */ + +Option.prototype.is = function(arg) { + return this.short === arg || this.long === arg; +}; + +/** + * Initialize a new `Command`. + * + * @param {String} name + * @api public + */ + +function Command(name) { + this.commands = []; + this.options = []; + this._execs = {}; + this._allowUnknownOption = false; + this._args = []; + this._name = name || ''; +} + +/** + * Add command `name`. + * + * The `.action()` callback is invoked when the + * command `name` is specified via __ARGV__, + * and the remaining arguments are applied to the + * function for access. + * + * When the `name` is "*" an un-matched command + * will be passed as the first arg, followed by + * the rest of __ARGV__ remaining. + * + * Examples: + * + * program + * .version('0.0.1') + * .option('-C, --chdir ', 'change the working directory') + * .option('-c, --config ', 'set config path. defaults to ./deploy.conf') + * .option('-T, --no-tests', 'ignore test hook') + * + * program + * .command('setup') + * .description('run remote setup commands') + * .action(function() { + * console.log('setup'); + * }); + * + * program + * .command('exec ') + * .description('run the given remote command') + * .action(function(cmd) { + * console.log('exec "%s"', cmd); + * }); + * + * program + * .command('teardown [otherDirs...]') + * .description('run teardown commands') + * .action(function(dir, otherDirs) { + * console.log('dir "%s"', dir); + * if (otherDirs) { + * otherDirs.forEach(function (oDir) { + * console.log('dir "%s"', oDir); + * }); + * } + * }); + * + * program + * .command('*') + * .description('deploy the given env') + * .action(function(env) { + * console.log('deploying "%s"', env); + * }); + * + * program.parse(process.argv); + * + * @param {String} name + * @param {String} [desc] for git-style sub-commands + * @return {Command} the new command + * @api public + */ + +Command.prototype.command = function(name, desc, opts) { + if (typeof desc === 'object' && desc !== null) { + opts = desc; + desc = null; + } + opts = opts || {}; + var args = name.split(/ +/); + var cmd = new Command(args.shift()); + + if (desc) { + cmd.description(desc); + this.executables = true; + this._execs[cmd._name] = true; + if (opts.isDefault) this.defaultExecutable = cmd._name; + } + cmd._noHelp = !!opts.noHelp; + this.commands.push(cmd); + cmd.parseExpectedArgs(args); + cmd.parent = this; + + if (desc) return this; + return cmd; +}; + +/** + * Define argument syntax for the top-level command. + * + * @api public + */ + +Command.prototype.arguments = function(desc) { + return this.parseExpectedArgs(desc.split(/ +/)); +}; + +/** + * Add an implicit `help [cmd]` subcommand + * which invokes `--help` for the given command. + * + * @api private + */ + +Command.prototype.addImplicitHelpCommand = function() { + this.command('help [cmd]', 'display help for [cmd]'); +}; + +/** + * Parse expected `args`. + * + * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`. + * + * @param {Array} args + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parseExpectedArgs = function(args) { + if (!args.length) return; + var self = this; + args.forEach(function(arg) { + var argDetails = { + required: false, + name: '', + variadic: false + }; + + switch (arg[0]) { + case '<': + argDetails.required = true; + argDetails.name = arg.slice(1, -1); + break; + case '[': + argDetails.name = arg.slice(1, -1); + break; + } + + if (argDetails.name.length > 3 && argDetails.name.slice(-3) === '...') { + argDetails.variadic = true; + argDetails.name = argDetails.name.slice(0, -3); + } + if (argDetails.name) { + self._args.push(argDetails); + } + }); + return this; +}; + +/** + * Register callback `fn` for the command. + * + * Examples: + * + * program + * .command('help') + * .description('display verbose help') + * .action(function() { + * // output help here + * }); + * + * @param {Function} fn + * @return {Command} for chaining + * @api public + */ + +Command.prototype.action = function(fn) { + var self = this; + var listener = function(args, unknown) { + // Parse any so-far unknown options + args = args || []; + unknown = unknown || []; + + var parsed = self.parseOptions(unknown); + + // Output help if necessary + outputHelpIfNecessary(self, parsed.unknown); + + // If there are still any unknown options, then we simply + // die, unless someone asked for help, in which case we give it + // to them, and then we die. + if (parsed.unknown.length > 0) { + self.unknownOption(parsed.unknown[0]); + } + + // Leftover arguments need to be pushed back. Fixes issue #56 + if (parsed.args.length) args = parsed.args.concat(args); + + self._args.forEach(function(arg, i) { + if (arg.required && args[i] == null) { + self.missingArgument(arg.name); + } else if (arg.variadic) { + if (i !== self._args.length - 1) { + self.variadicArgNotLast(arg.name); + } + + args[i] = args.splice(i); + } + }); + + // Always append ourselves to the end of the arguments, + // to make sure we match the number of arguments the user + // expects + if (self._args.length) { + args[self._args.length] = self; + } else { + args.push(self); + } + + fn.apply(self, args); + }; + var parent = this.parent || this; + var name = parent === this ? '*' : this._name; + parent.on('command:' + name, listener); + if (this._alias) parent.on('command:' + this._alias, listener); + return this; +}; + +/** + * Define option with `flags`, `description` and optional + * coercion `fn`. + * + * The `flags` string should contain both the short and long flags, + * separated by comma, a pipe or space. The following are all valid + * all will output this way when `--help` is used. + * + * "-p, --pepper" + * "-p|--pepper" + * "-p --pepper" + * + * Examples: + * + * // simple boolean defaulting to false + * program.option('-p, --pepper', 'add pepper'); + * + * --pepper + * program.pepper + * // => Boolean + * + * // simple boolean defaulting to true + * program.option('-C, --no-cheese', 'remove cheese'); + * + * program.cheese + * // => true + * + * --no-cheese + * program.cheese + * // => false + * + * // required argument + * program.option('-C, --chdir ', 'change the working directory'); + * + * --chdir /tmp + * program.chdir + * // => "/tmp" + * + * // optional argument + * program.option('-c, --cheese [type]', 'add cheese [marble]'); + * + * @param {String} flags + * @param {String} description + * @param {Function|*} [fn] or default + * @param {*} [defaultValue] + * @return {Command} for chaining + * @api public + */ + +Command.prototype.option = function(flags, description, fn, defaultValue) { + var self = this, + option = new Option(flags, description), + oname = option.name(), + name = option.attributeName(); + + // default as 3rd arg + if (typeof fn !== 'function') { + if (fn instanceof RegExp) { + var regex = fn; + fn = function(val, def) { + var m = regex.exec(val); + return m ? m[0] : def; + }; + } else { + defaultValue = fn; + fn = null; + } + } + + // preassign default value only for --no-*, [optional], or + if (!option.bool || option.optional || option.required) { + // when --no-* we make sure default is true + if (!option.bool) defaultValue = true; + // preassign only if we have a default + if (defaultValue !== undefined) { + self[name] = defaultValue; + option.defaultValue = defaultValue; + } + } + + // register the option + this.options.push(option); + + // when it's passed assign the value + // and conditionally invoke the callback + this.on('option:' + oname, function(val) { + // coercion + if (val !== null && fn) { + val = fn(val, self[name] === undefined ? defaultValue : self[name]); + } + + // unassigned or bool + if (typeof self[name] === 'boolean' || typeof self[name] === 'undefined') { + // if no value, bool true, and we have a default, then use it! + if (val == null) { + self[name] = option.bool + ? defaultValue || true + : false; + } else { + self[name] = val; + } + } else if (val !== null) { + // reassign + self[name] = val; + } + }); + + return this; +}; + +/** + * Allow unknown options on the command line. + * + * @param {Boolean} arg if `true` or omitted, no error will be thrown + * for unknown options. + * @api public + */ +Command.prototype.allowUnknownOption = function(arg) { + this._allowUnknownOption = arguments.length === 0 || arg; + return this; +}; + +/** + * Parse `argv`, settings options and invoking commands when defined. + * + * @param {Array} argv + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parse = function(argv) { + // implicit help + if (this.executables) this.addImplicitHelpCommand(); + + // store raw args + this.rawArgs = argv; + + // guess name + this._name = this._name || basename(argv[1], '.js'); + + // github-style sub-commands with no sub-command + if (this.executables && argv.length < 3 && !this.defaultExecutable) { + // this user needs help + argv.push('--help'); + } + + // process argv + var parsed = this.parseOptions(this.normalize(argv.slice(2))); + var args = this.args = parsed.args; + + var result = this.parseArgs(this.args, parsed.unknown); + + // executable sub-commands + var name = result.args[0]; + + var aliasCommand = null; + // check alias of sub commands + if (name) { + aliasCommand = this.commands.filter(function(command) { + return command.alias() === name; + })[0]; + } + + if (this._execs[name] && typeof this._execs[name] !== 'function') { + return this.executeSubCommand(argv, args, parsed.unknown); + } else if (aliasCommand) { + // is alias of a subCommand + args[0] = aliasCommand._name; + return this.executeSubCommand(argv, args, parsed.unknown); + } else if (this.defaultExecutable) { + // use the default subcommand + args.unshift(this.defaultExecutable); + return this.executeSubCommand(argv, args, parsed.unknown); + } + + return result; +}; + +/** + * Execute a sub-command executable. + * + * @param {Array} argv + * @param {Array} args + * @param {Array} unknown + * @api private + */ + +Command.prototype.executeSubCommand = function(argv, args, unknown) { + args = args.concat(unknown); + + if (!args.length) this.help(); + if (args[0] === 'help' && args.length === 1) this.help(); + + // --help + if (args[0] === 'help') { + args[0] = args[1]; + args[1] = '--help'; + } + + // executable + var f = argv[1]; + // name of the subcommand, link `pm-install` + var bin = basename(f, '.js') + '-' + args[0]; + + // In case of globally installed, get the base dir where executable + // subcommand file should be located at + var baseDir, + link = fs.lstatSync(f).isSymbolicLink() ? fs.readlinkSync(f) : f; + + // when symbolink is relative path + if (link !== f && link.charAt(0) !== '/') { + link = path.join(dirname(f), link); + } + baseDir = dirname(link); + + // prefer local `./` to bin in the $PATH + var localBin = path.join(baseDir, bin); + + // whether bin file is a js script with explicit `.js` extension + var isExplicitJS = false; + if (exists(localBin + '.js')) { + bin = localBin + '.js'; + isExplicitJS = true; + } else if (exists(localBin)) { + bin = localBin; + } + + args = args.slice(1); + + var proc; + if (process.platform !== 'win32') { + if (isExplicitJS) { + args.unshift(bin); + // add executable arguments to spawn + args = (process.execArgv || []).concat(args); + + proc = spawn(process.argv[0], args, { stdio: 'inherit', customFds: [0, 1, 2] }); + } else { + proc = spawn(bin, args, { stdio: 'inherit', customFds: [0, 1, 2] }); + } + } else { + args.unshift(bin); + proc = spawn(process.execPath, args, { stdio: 'inherit' }); + } + + var signals = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP']; + signals.forEach(function(signal) { + process.on(signal, function() { + if (proc.killed === false && proc.exitCode === null) { + proc.kill(signal); + } + }); + }); + proc.on('close', process.exit.bind(process)); + proc.on('error', function(err) { + if (err.code === 'ENOENT') { + console.error('\n %s(1) does not exist, try --help\n', bin); + } else if (err.code === 'EACCES') { + console.error('\n %s(1) not executable. try chmod or run with root\n', bin); + } + process.exit(1); + }); + + // Store the reference to the child process + this.runningCommand = proc; +}; + +/** + * Normalize `args`, splitting joined short flags. For example + * the arg "-abc" is equivalent to "-a -b -c". + * This also normalizes equal sign and splits "--abc=def" into "--abc def". + * + * @param {Array} args + * @return {Array} + * @api private + */ + +Command.prototype.normalize = function(args) { + var ret = [], + arg, + lastOpt, + index; + + for (var i = 0, len = args.length; i < len; ++i) { + arg = args[i]; + if (i > 0) { + lastOpt = this.optionFor(args[i - 1]); + } + + if (arg === '--') { + // Honor option terminator + ret = ret.concat(args.slice(i)); + break; + } else if (lastOpt && lastOpt.required) { + ret.push(arg); + } else if (arg.length > 1 && arg[0] === '-' && arg[1] !== '-') { + arg.slice(1).split('').forEach(function(c) { + ret.push('-' + c); + }); + } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) { + ret.push(arg.slice(0, index), arg.slice(index + 1)); + } else { + ret.push(arg); + } + } + + return ret; +}; + +/** + * Parse command `args`. + * + * When listener(s) are available those + * callbacks are invoked, otherwise the "*" + * event is emitted and those actions are invoked. + * + * @param {Array} args + * @return {Command} for chaining + * @api private + */ + +Command.prototype.parseArgs = function(args, unknown) { + var name; + + if (args.length) { + name = args[0]; + if (this.listeners('command:' + name).length) { + this.emit('command:' + args.shift(), args, unknown); + } else { + this.emit('command:*', args); + } + } else { + outputHelpIfNecessary(this, unknown); + + // If there were no args and we have unknown options, + // then they are extraneous and we need to error. + if (unknown.length > 0) { + this.unknownOption(unknown[0]); + } + } + + return this; +}; + +/** + * Return an option matching `arg` if any. + * + * @param {String} arg + * @return {Option} + * @api private + */ + +Command.prototype.optionFor = function(arg) { + for (var i = 0, len = this.options.length; i < len; ++i) { + if (this.options[i].is(arg)) { + return this.options[i]; + } + } +}; + +/** + * Parse options from `argv` returning `argv` + * void of these options. + * + * @param {Array} argv + * @return {Array} + * @api public + */ + +Command.prototype.parseOptions = function(argv) { + var args = [], + len = argv.length, + literal, + option, + arg; + + var unknownOptions = []; + + // parse options + for (var i = 0; i < len; ++i) { + arg = argv[i]; + + // literal args after -- + if (literal) { + args.push(arg); + continue; + } + + if (arg === '--') { + literal = true; + continue; + } + + // find matching Option + option = this.optionFor(arg); + + // option is defined + if (option) { + // requires arg + if (option.required) { + arg = argv[++i]; + if (arg == null) return this.optionMissingArgument(option); + this.emit('option:' + option.name(), arg); + // optional arg + } else if (option.optional) { + arg = argv[i + 1]; + if (arg == null || (arg[0] === '-' && arg !== '-')) { + arg = null; + } else { + ++i; + } + this.emit('option:' + option.name(), arg); + // bool + } else { + this.emit('option:' + option.name()); + } + continue; + } + + // looks like an option + if (arg.length > 1 && arg[0] === '-') { + unknownOptions.push(arg); + + // If the next argument looks like it might be + // an argument for this option, we pass it on. + // If it isn't, then it'll simply be ignored + if ((i + 1) < argv.length && argv[i + 1][0] !== '-') { + unknownOptions.push(argv[++i]); + } + continue; + } + + // arg + args.push(arg); + } + + return { args: args, unknown: unknownOptions }; +}; + +/** + * Return an object containing options as key-value pairs + * + * @return {Object} + * @api public + */ +Command.prototype.opts = function() { + var result = {}, + len = this.options.length; + + for (var i = 0; i < len; i++) { + var key = this.options[i].attributeName(); + result[key] = key === this._versionOptionName ? this._version : this[key]; + } + return result; +}; + +/** + * Argument `name` is missing. + * + * @param {String} name + * @api private + */ + +Command.prototype.missingArgument = function(name) { + console.error(); + console.error(" error: missing required argument `%s'", name); + console.error(); + process.exit(1); +}; + +/** + * `Option` is missing an argument, but received `flag` or nothing. + * + * @param {String} option + * @param {String} flag + * @api private + */ + +Command.prototype.optionMissingArgument = function(option, flag) { + console.error(); + if (flag) { + console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag); + } else { + console.error(" error: option `%s' argument missing", option.flags); + } + console.error(); + process.exit(1); +}; + +/** + * Unknown option `flag`. + * + * @param {String} flag + * @api private + */ + +Command.prototype.unknownOption = function(flag) { + if (this._allowUnknownOption) return; + console.error(); + console.error(" error: unknown option `%s'", flag); + console.error(); + process.exit(1); +}; + +/** + * Variadic argument with `name` is not the last argument as required. + * + * @param {String} name + * @api private + */ + +Command.prototype.variadicArgNotLast = function(name) { + console.error(); + console.error(" error: variadic arguments must be last `%s'", name); + console.error(); + process.exit(1); +}; + +/** + * Set the program version to `str`. + * + * This method auto-registers the "-V, --version" flag + * which will print the version number when passed. + * + * @param {String} str + * @param {String} [flags] + * @return {Command} for chaining + * @api public + */ + +Command.prototype.version = function(str, flags) { + if (arguments.length === 0) return this._version; + this._version = str; + flags = flags || '-V, --version'; + var versionOption = new Option(flags, 'output the version number'); + this._versionOptionName = versionOption.long.substr(2) || 'version'; + this.options.push(versionOption); + this.on('option:' + this._versionOptionName, function() { + process.stdout.write(str + '\n'); + process.exit(0); + }); + return this; +}; + +/** + * Set the description to `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.description = function(str) { + if (arguments.length === 0) return this._description; + this._description = str; + return this; +}; + +/** + * Set an alias for the command + * + * @param {String} alias + * @return {String|Command} + * @api public + */ + +Command.prototype.alias = function(alias) { + var command = this; + if (this.commands.length !== 0) { + command = this.commands[this.commands.length - 1]; + } + + if (arguments.length === 0) return command._alias; + + if (alias === command._name) throw new Error('Command alias can\'t be the same as its name'); + + command._alias = alias; + return this; +}; + +/** + * Set / get the command usage `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.usage = function(str) { + var args = this._args.map(function(arg) { + return humanReadableArgName(arg); + }); + + var usage = '[options]' + + (this.commands.length ? ' [command]' : '') + + (this._args.length ? ' ' + args.join(' ') : ''); + + if (arguments.length === 0) return this._usage || usage; + this._usage = str; + + return this; +}; + +/** + * Get or set the name of the command + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.name = function(str) { + if (arguments.length === 0) return this._name; + this._name = str; + return this; +}; + +/** + * Return the largest option length. + * + * @return {Number} + * @api private + */ + +Command.prototype.largestOptionLength = function() { + return this.options.reduce(function(max, option) { + return Math.max(max, option.flags.length); + }, 0); +}; + +/** + * Return help for options. + * + * @return {String} + * @api private + */ + +Command.prototype.optionHelp = function() { + var width = this.largestOptionLength(); + + // Append the help information + return this.options.map(function(option) { + return pad(option.flags, width) + ' ' + option.description + + ((option.bool && option.defaultValue !== undefined) ? ' (default: ' + option.defaultValue + ')' : ''); + }).concat([pad('-h, --help', width) + ' ' + 'output usage information']) + .join('\n'); +}; + +/** + * Return command help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.commandHelp = function() { + if (!this.commands.length) return ''; + + var commands = this.commands.filter(function(cmd) { + return !cmd._noHelp; + }).map(function(cmd) { + var args = cmd._args.map(function(arg) { + return humanReadableArgName(arg); + }).join(' '); + + return [ + cmd._name + + (cmd._alias ? '|' + cmd._alias : '') + + (cmd.options.length ? ' [options]' : '') + + (args ? ' ' + args : ''), + cmd._description + ]; + }); + + var width = commands.reduce(function(max, command) { + return Math.max(max, command[0].length); + }, 0); + + return [ + '', + ' Commands:', + '', + commands.map(function(cmd) { + var desc = cmd[1] ? ' ' + cmd[1] : ''; + return (desc ? pad(cmd[0], width) : cmd[0]) + desc; + }).join('\n').replace(/^/gm, ' '), + '' + ].join('\n'); +}; + +/** + * Return program help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.helpInformation = function() { + var desc = []; + if (this._description) { + desc = [ + ' ' + this._description, + '' + ]; + } + + var cmdName = this._name; + if (this._alias) { + cmdName = cmdName + '|' + this._alias; + } + var usage = [ + '', + ' Usage: ' + cmdName + ' ' + this.usage(), + '' + ]; + + var cmds = []; + var commandHelp = this.commandHelp(); + if (commandHelp) cmds = [commandHelp]; + + var options = [ + '', + ' Options:', + '', + '' + this.optionHelp().replace(/^/gm, ' '), + '' + ]; + + return usage + .concat(desc) + .concat(options) + .concat(cmds) + .join('\n'); +}; + +/** + * Output help information for this command + * + * @api public + */ + +Command.prototype.outputHelp = function(cb) { + if (!cb) { + cb = function(passthru) { + return passthru; + }; + } + process.stdout.write(cb(this.helpInformation())); + this.emit('--help'); +}; + +/** + * Output help information and exit. + * + * @api public + */ + +Command.prototype.help = function(cb) { + this.outputHelp(cb); + process.exit(); +}; + +/** + * Camel-case the given `flag` + * + * @param {String} flag + * @return {String} + * @api private + */ + +function camelcase(flag) { + return flag.split('-').reduce(function(str, word) { + return str + word[0].toUpperCase() + word.slice(1); + }); +} + +/** + * Pad `str` to `width`. + * + * @param {String} str + * @param {Number} width + * @return {String} + * @api private + */ + +function pad(str, width) { + var len = Math.max(0, width - str.length); + return str + Array(len + 1).join(' '); +} + +/** + * Output help information if necessary + * + * @param {Command} command to output help for + * @param {Array} array of options to search for -h or --help + * @api private + */ + +function outputHelpIfNecessary(cmd, options) { + options = options || []; + for (var i = 0; i < options.length; i++) { + if (options[i] === '--help' || options[i] === '-h') { + cmd.outputHelp(); + process.exit(0); + } + } +} + +/** + * Takes an argument an returns its human readable equivalent for help usage. + * + * @param {Object} arg + * @return {String} + * @api private + */ + +function humanReadableArgName(arg) { + var nameOutput = arg.name + (arg.variadic === true ? '...' : ''); + + return arg.required + ? '<' + nameOutput + '>' + : '[' + nameOutput + ']'; +} + +// for versions before node v0.8 when there weren't `fs.existsSync` +function exists(file) { + try { + if (fs.statSync(file).isFile()) { + return true; + } + } catch (e) { + return false; + } +} diff --git a/octorun/node_modules/commander/package.json b/octorun/node_modules/commander/package.json new file mode 100644 index 000000000..b33979d03 --- /dev/null +++ b/octorun/node_modules/commander/package.json @@ -0,0 +1,114 @@ +{ + "_args": [ + [ + "commander@^2.14.1", + "C:\\Users\\Spade\\Projects\\GitHub\\Unity\\octorun" + ] + ], + "_from": "commander@>=2.14.1 <3.0.0", + "_id": "commander@2.14.1", + "_inCache": true, + "_location": "/commander", + "_nodeVersion": "9.4.0", + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages", + "tmp": "tmp/commander_2.14.1_1517989378540_0.7122613806538618" + }, + "_npmUser": { + "email": "abe@enzou.tokyo", + "name": "abetomo" + }, + "_npmVersion": "5.6.0", + "_phantomChildren": {}, + "_requested": { + "name": "commander", + "raw": "commander@^2.14.1", + "rawSpec": "^2.14.1", + "scope": null, + "spec": ">=2.14.1 <3.0.0", + "type": "range" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", + "_shasum": "2235123e37af8ca3c65df45b026dbd357b01b9aa", + "_shrinkwrap": null, + "_spec": "commander@^2.14.1", + "_where": "C:\\Users\\Spade\\Projects\\GitHub\\Unity\\octorun", + "author": { + "email": "tj@vision-media.ca", + "name": "TJ Holowaychuk" + }, + "bugs": { + "url": "https://github.com/tj/commander.js/issues" + }, + "dependencies": {}, + "description": "the complete solution for node.js command-line programs", + "devDependencies": { + "@types/node": "^7.0.52", + "eslint": "^3.19.0", + "should": "^11.2.1", + "sinon": "^2.4.1", + "standard": "^10.0.3", + "typescript": "^2.7.1" + }, + "directories": {}, + "dist": { + "fileCount": 6, + "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==", + "shasum": "2235123e37af8ca3c65df45b026dbd357b01b9aa", + "tarball": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", + "unpackedSize": 58015 + }, + "files": [ + "index.js", + "typings/index.d.ts" + ], + "gitHead": "6b026a5c88a2c7f67db70831c015e9d11c7babca", + "homepage": "https://github.com/tj/commander.js#readme", + "installable": true, + "keywords": [ + "command", + "commander", + "option", + "parser" + ], + "license": "MIT", + "main": "index", + "maintainers": [ + { + "email": "abe@enzou.tokyo", + "name": "abetomo" + }, + { + "email": "rkoutnik@gmail.com", + "name": "somekittens" + }, + { + "email": "tj@vision-media.ca", + "name": "tjholowaychuk" + }, + { + "email": "romain.vanesyan@gmail.com", + "name": "vanesyan" + }, + { + "email": "zhiyelee@gmail.com", + "name": "zhiyelee" + } + ], + "name": "commander", + "optionalDependencies": {}, + "repository": { + "type": "git", + "url": "git+https://github.com/tj/commander.js.git" + }, + "scripts": { + "lint": "eslint index.js", + "test": "make test && npm run test-typings", + "test-typings": "node_modules/typescript/bin/tsc -p tsconfig.json" + }, + "typings": "typings/index.d.ts", + "version": "2.14.1" +} diff --git a/octorun/node_modules/commander/typings/index.d.ts b/octorun/node_modules/commander/typings/index.d.ts new file mode 100644 index 000000000..483076741 --- /dev/null +++ b/octorun/node_modules/commander/typings/index.d.ts @@ -0,0 +1,309 @@ +// Type definitions for commander 2.11 +// Project: https://github.com/visionmedia/commander.js +// Definitions by: Alan Agius , Marcelo Dezem , vvakame , Jules Randolph +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +declare namespace local { + + class Option { + flags: string; + required: boolean; + optional: boolean; + bool: boolean; + short?: string; + long: string; + description: string; + + /** + * Initialize a new `Option` with the given `flags` and `description`. + * + * @param {string} flags + * @param {string} [description] + */ + constructor(flags: string, description?: string); + } + + class Command extends NodeJS.EventEmitter { + [key: string]: any; + + args: string[]; + + /** + * Initialize a new `Command`. + * + * @param {string} [name] + */ + constructor(name?: string); + + /** + * Set the program version to `str`. + * + * This method auto-registers the "-V, --version" flag + * which will print the version number when passed. + * + * @param {string} str + * @param {string} [flags] + * @returns {Command} for chaining + */ + version(str: string, flags?: string): Command; + + /** + * Add command `name`. + * + * The `.action()` callback is invoked when the + * command `name` is specified via __ARGV__, + * and the remaining arguments are applied to the + * function for access. + * + * When the `name` is "*" an un-matched command + * will be passed as the first arg, followed by + * the rest of __ARGV__ remaining. + * + * @example + * program + * .version('0.0.1') + * .option('-C, --chdir ', 'change the working directory') + * .option('-c, --config ', 'set config path. defaults to ./deploy.conf') + * .option('-T, --no-tests', 'ignore test hook') + * + * program + * .command('setup') + * .description('run remote setup commands') + * .action(function() { + * console.log('setup'); + * }); + * + * program + * .command('exec ') + * .description('run the given remote command') + * .action(function(cmd) { + * console.log('exec "%s"', cmd); + * }); + * + * program + * .command('teardown [otherDirs...]') + * .description('run teardown commands') + * .action(function(dir, otherDirs) { + * console.log('dir "%s"', dir); + * if (otherDirs) { + * otherDirs.forEach(function (oDir) { + * console.log('dir "%s"', oDir); + * }); + * } + * }); + * + * program + * .command('*') + * .description('deploy the given env') + * .action(function(env) { + * console.log('deploying "%s"', env); + * }); + * + * program.parse(process.argv); + * + * @param {string} name + * @param {string} [desc] for git-style sub-commands + * @param {CommandOptions} [opts] command options + * @returns {Command} the new command + */ + command(name: string, desc?: string, opts?: commander.CommandOptions): Command; + + /** + * Define argument syntax for the top-level command. + * + * @param {string} desc + * @returns {Command} for chaining + */ + arguments(desc: string): Command; + + /** + * Parse expected `args`. + * + * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`. + * + * @param {string[]} args + * @returns {Command} for chaining + */ + parseExpectedArgs(args: string[]): Command; + + /** + * Register callback `fn` for the command. + * + * @example + * program + * .command('help') + * .description('display verbose help') + * .action(function() { + * // output help here + * }); + * + * @param {(...args: any[]) => void} fn + * @returns {Command} for chaining + */ + action(fn: (...args: any[]) => void): Command; + + /** + * Define option with `flags`, `description` and optional + * coercion `fn`. + * + * The `flags` string should contain both the short and long flags, + * separated by comma, a pipe or space. The following are all valid + * all will output this way when `--help` is used. + * + * "-p, --pepper" + * "-p|--pepper" + * "-p --pepper" + * + * @example + * // simple boolean defaulting to false + * program.option('-p, --pepper', 'add pepper'); + * + * --pepper + * program.pepper + * // => Boolean + * + * // simple boolean defaulting to true + * program.option('-C, --no-cheese', 'remove cheese'); + * + * program.cheese + * // => true + * + * --no-cheese + * program.cheese + * // => false + * + * // required argument + * program.option('-C, --chdir ', 'change the working directory'); + * + * --chdir /tmp + * program.chdir + * // => "/tmp" + * + * // optional argument + * program.option('-c, --cheese [type]', 'add cheese [marble]'); + * + * @param {string} flags + * @param {string} [description] + * @param {((arg1: any, arg2: any) => void) | RegExp} [fn] function or default + * @param {*} [defaultValue] + * @returns {Command} for chaining + */ + option(flags: string, description?: string, fn?: ((arg1: any, arg2: any) => void) | RegExp, defaultValue?: any): Command; + option(flags: string, description?: string, defaultValue?: any): Command; + + /** + * Allow unknown options on the command line. + * + * @param {boolean} [arg] if `true` or omitted, no error will be thrown for unknown options. + * @returns {Command} for chaining + */ + allowUnknownOption(arg?: boolean): Command; + + /** + * Parse `argv`, settings options and invoking commands when defined. + * + * @param {string[]} argv + * @returns {Command} for chaining + */ + parse(argv: string[]): Command; + + /** + * Parse options from `argv` returning `argv` void of these options. + * + * @param {string[]} argv + * @returns {ParseOptionsResult} + */ + parseOptions(argv: string[]): commander.ParseOptionsResult; + + /** + * Return an object containing options as key-value pairs + * + * @returns {{[key: string]: string}} + */ + opts(): { [key: string]: string }; + + /** + * Set the description to `str`. + * + * @param {string} str + * @return {(Command | string)} + */ + description(str: string): Command; + description(): string; + + /** + * Set an alias for the command. + * + * @param {string} alias + * @return {(Command | string)} + */ + alias(alias: string): Command; + alias(): string; + + /** + * Set or get the command usage. + * + * @param {string} str + * @return {(Command | string)} + */ + usage(str: string): Command; + usage(): string; + + /** + * Set the name of the command. + * + * @param {string} str + * @return {Command} + */ + name(str: string): Command; + + /** + * Get the name of the command. + * + * @return {string} + */ + name(): string; + + /** + * Output help information for this command. + * + * @param {(str: string) => string} [cb] + */ + outputHelp(cb?: (str: string) => string): void; + + /** Output help information and exit. + * + * @param {(str: string) => string} [cb] + */ + help(cb?: (str: string) => string): void; + } + +} + +declare namespace commander { + + type Command = local.Command + + type Option = local.Option + + interface CommandOptions { + noHelp?: boolean; + isDefault?: boolean; + } + + interface ParseOptionsResult { + args: string[]; + unknown: string[]; + } + + interface CommanderStatic extends Command { + Command: typeof local.Command; + Option: typeof local.Option; + CommandOptions: CommandOptions; + ParseOptionsResult: ParseOptionsResult; + } + +} + +declare const commander: commander.CommanderStatic; +export = commander; diff --git a/octorun/node_modules/dotenv/.editorconfig b/octorun/node_modules/dotenv/.editorconfig new file mode 100644 index 000000000..5d1263484 --- /dev/null +++ b/octorun/node_modules/dotenv/.editorconfig @@ -0,0 +1,13 @@ +# editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/octorun/node_modules/dotenv/.npmignore b/octorun/node_modules/dotenv/.npmignore new file mode 100644 index 000000000..519e4f277 --- /dev/null +++ b/octorun/node_modules/dotenv/.npmignore @@ -0,0 +1,12 @@ +# Coverage directory used by tools like istanbul +coverage + +# Dependency directory +# Commenting this out is preferred by some people, see +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- +node_modules + +# Users Environment Variables +.lock-wscript + +.DS_Store diff --git a/octorun/node_modules/dotenv/.travis.yml b/octorun/node_modules/dotenv/.travis.yml new file mode 100644 index 000000000..ba0b1445c --- /dev/null +++ b/octorun/node_modules/dotenv/.travis.yml @@ -0,0 +1,6 @@ +language: node_js + +node_js: + - iojs + - 0.12 + - 0.10 diff --git a/octorun/node_modules/dotenv/Contributing.md b/octorun/node_modules/dotenv/Contributing.md new file mode 100644 index 000000000..04552a9e0 --- /dev/null +++ b/octorun/node_modules/dotenv/Contributing.md @@ -0,0 +1,25 @@ +# Contributing + +1. Fork it +2. `npm install` +3. Create your feature branch (`git checkout -b my-new-feature`) +4. Commit your changes (`git commit -am 'Added some feature'`) +5. `npm test` +6. Push to the branch (`git push origin my-new-feature`) +7. Create new Pull Request + +## Testing + +We use [lab](https://github.com/hapijs/lab) and [should](https://github.com/shouldjs/should.js) to write BDD test. Run our test suite with this command: + +``` +npm test +``` + +## Code Style + +We use [standard](https://www.npmjs.com/package/standard) and [editorconfig](http://editorconfig.org) to maintain code style and best practices. Please make sure your PR adheres to the guides by running: + +``` +npm run lint +``` diff --git a/octorun/node_modules/dotenv/README.md b/octorun/node_modules/dotenv/README.md new file mode 100644 index 000000000..de324261a --- /dev/null +++ b/octorun/node_modules/dotenv/README.md @@ -0,0 +1,198 @@ +# dotenv + +dotenv + +Dotenv loads environment variables from `.env` into `ENV` (process.env). + +[![BuildStatus](https://img.shields.io/travis/motdotla/dotenv/master.svg?style=flat-square)](https://travis-ci.org/motdotla/dotenv) +[![NPM version](https://img.shields.io/npm/v/dotenv.svg?style=flat-square)](https://www.npmjs.com/package/dotenv) +[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard) + +> "Storing [configuration in the environment](http://www.12factor.net/config) +> is one of the tenets of a [twelve-factor app](http://www.12factor.net/). +> Anything that is likely to change between deployment environments–such as +> resource handles for databases or credentials for external services–should be +> extracted from the code into environment variables. +> +> But it is not always practical to set environment variables on development +> machines or continuous integration servers where multiple projects are run. +> Dotenv loads variables from a `.env` file into ENV when the environment is +> bootstrapped." +> +> [Brandon Keepers' Dotenv in Ruby](https://github.com/bkeepers/dotenv) + +## Install + +```bash +npm install dotenv --save +``` + +## Usage + +As early as possible in your application, require and load dotenv. + +```javascript +require('dotenv').load(); +``` + +Create a `.env` file in the root directory of your project. Add +environment-specific variables on new lines in the form of `NAME=VALUE`. +For example: + +``` +DB_HOST=localhost +DB_USER=root +DB_PASS=s1mpl3 +``` + +That's it. + +`process.env` now has the keys and values you defined in your `.env` file. + +```javascript +db.connect({ + host: process.env.DB_HOST, + username: process.env.DB_USER, + password: process.env.DB_PASS +}); +``` + +### Preload + +If you are using iojs-v1.6.0 or later, you can use the `--require` (`-r`) command line option to preload dotenv. By doing this, you do not need to require and load dotenv in your application code. + + +```bash +$ node -r dotenv/config your_script.js +``` + +The configuration options below are supported as command line arguments in the format `dotenv_config_