Skip to content

Commit 8937c25

Browse files
committed
use git cmd for init in GitTools.Testing
1 parent 7b3079c commit 8937c25

File tree

6 files changed

+256
-5
lines changed

6 files changed

+256
-5
lines changed

src/GitTools.Testing/Fixtures/EmptyRepositoryFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public EmptyRepositoryFixture() : base(CreateNewRepository)
1111

1212
private static IRepository CreateNewRepository(string path)
1313
{
14-
LibGit2Sharp.Repository.Init(path);
14+
Init(path);
1515
Console.WriteLine("Created git repository at '{0}'", path);
1616

1717
return new Repository(path);

src/GitTools.Testing/Fixtures/RemoteRepositoryFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public RemoteRepositoryFixture() : this(CreateNewRepository)
2727

2828
private static IRepository CreateNewRepository(string path)
2929
{
30-
LibGit2Sharp.Repository.Init(path);
30+
Init(path);
3131
Console.WriteLine("Created git repository at '{0}'", path);
3232

3333
var repo = new Repository(path);

src/GitTools.Testing/Fixtures/RepositoryFixtureBase.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ public void Checkout(string branch)
6464
Commands.Checkout(Repository, branch);
6565
}
6666

67+
public static void Init(string path)
68+
{
69+
GitTestExtensions.ExecuteGitCmd($"init {path} -b master");
70+
}
71+
6772
public void MakeATaggedCommit(string tag)
6873
{
6974
MakeACommit();

src/GitTools.Testing/GitTestExtensions.cs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
22
using System.IO;
33
using System.Linq;
4+
using System.Text;
5+
using GitTools.Testing.Internal;
46
using LibGit2Sharp;
57

68
namespace GitTools.Testing
@@ -34,7 +36,7 @@ public static Commit[] MakeCommits(this IRepository repository, int numCommitsTo
3436
.ToArray();
3537
}
3638

37-
public static Commit CreateFileAndCommit(this IRepository repository, string relativeFileName, string commitMessage = null)
39+
private static Commit CreateFileAndCommit(this IRepository repository, string relativeFileName, string commitMessage = null)
3840
{
3941
var randomFile = Path.Combine(repository.Info.WorkingDirectory, relativeFileName);
4042
if (File.Exists(randomFile))
@@ -48,7 +50,7 @@ public static Commit CreateFileAndCommit(this IRepository repository, string rel
4850

4951
Commands.Stage(repository, randomFile);
5052

51-
return repository.Commit(string.Format("Test Commit for file '{0}' - {1}", relativeFileName, commitMessage),
53+
return repository.Commit($"Test Commit for file '{relativeFileName}' - {commitMessage}",
5254
Generate.SignatureNow(), Generate.SignatureNow());
5355
}
5456

@@ -83,5 +85,39 @@ public static Commit CreatePullRequestRef(this IRepository repository, string fr
8385

8486
return commit;
8587
}
88+
89+
public static void ExecuteGitCmd(string gitCmd, Action<string> writer = null)
90+
{
91+
var output = new StringBuilder();
92+
try
93+
{
94+
ProcessHelper.Run(
95+
o => output.AppendLine(o),
96+
e => output.AppendLineFormat("ERROR: {0}", e),
97+
null,
98+
"git",
99+
gitCmd,
100+
".");
101+
}
102+
catch (FileNotFoundException exception)
103+
{
104+
if (exception.FileName != "git")
105+
{
106+
throw;
107+
}
108+
109+
output.AppendLine("Could not execute 'git log' due to the following error:");
110+
output.AppendLine(exception.ToString());
111+
}
112+
113+
if (writer != null)
114+
{
115+
writer(output.ToString());
116+
}
117+
else
118+
{
119+
Console.Write(output.ToString());
120+
}
121+
}
86122
}
87123
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.ComponentModel;
4+
using System.Diagnostics;
5+
using System.IO;
6+
using System.Runtime.InteropServices;
7+
using System.Threading;
8+
9+
namespace GitTools.Testing.Internal
10+
{
11+
public static class ProcessHelper
12+
{
13+
private static readonly object LockObject = new object();
14+
15+
// http://social.msdn.microsoft.com/Forums/en/netfxbcl/thread/f6069441-4ab1-4299-ad6a-b8bb9ed36be3
16+
private static Process Start(ProcessStartInfo startInfo)
17+
{
18+
Process process;
19+
20+
lock (LockObject)
21+
{
22+
using (new ChangeErrorMode(ErrorModes.FailCriticalErrors | ErrorModes.NoGpFaultErrorBox))
23+
{
24+
try
25+
{
26+
process = Process.Start(startInfo);
27+
}
28+
catch (Win32Exception exception)
29+
{
30+
switch ((NativeErrorCode)exception.NativeErrorCode)
31+
{
32+
case NativeErrorCode.Success:
33+
// Success is not a failure.
34+
break;
35+
36+
case NativeErrorCode.FileNotFound:
37+
throw new FileNotFoundException($"The executable file '{startInfo.FileName}' could not be found.",
38+
startInfo.FileName,
39+
exception);
40+
41+
case NativeErrorCode.PathNotFound:
42+
throw new DirectoryNotFoundException($"The path to the executable file '{startInfo.FileName}' could not be found.",
43+
exception);
44+
}
45+
46+
throw;
47+
}
48+
49+
try
50+
{
51+
if (process != null)
52+
{
53+
process.PriorityClass = ProcessPriorityClass.Idle;
54+
}
55+
}
56+
catch
57+
{
58+
// NOTE: It seems like in some situations, setting the priority class will throw a Win32Exception
59+
// with the error code set to "Success", which I think we can safely interpret as a success and
60+
// not an exception.
61+
//
62+
// See: https://travis-ci.org/GitTools/GitVersion/jobs/171288284#L2026
63+
// And: https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382.aspx
64+
//
65+
// There's also the case where the process might be killed before we try to adjust its priority
66+
// class, in which case it will throw an InvalidOperationException. What we ideally should do
67+
// is start the process in a "suspended" state, adjust the priority class, then resume it, but
68+
// that's not possible in pure .NET.
69+
//
70+
// See: https://travis-ci.org/GitTools/GitVersion/jobs/166709203#L2278
71+
// And: http://www.codeproject.com/Articles/230005/Launch-a-process-suspended
72+
//
73+
// -- @asbjornu
74+
}
75+
}
76+
}
77+
78+
return process;
79+
}
80+
81+
// http://csharptest.net/532/using-processstart-to-capture-console-output/
82+
public static int Run(Action<string> output, Action<string> errorOutput, TextReader input, string exe, string args, string workingDirectory, params KeyValuePair<string, string>[] environmentalVariables)
83+
{
84+
if (string.IsNullOrEmpty(exe))
85+
throw new ArgumentNullException(nameof(exe));
86+
if (output == null)
87+
throw new ArgumentNullException(nameof(output));
88+
89+
workingDirectory ??= Environment.CurrentDirectory;
90+
91+
var psi = new ProcessStartInfo
92+
{
93+
UseShellExecute = false,
94+
RedirectStandardError = true,
95+
RedirectStandardOutput = true,
96+
RedirectStandardInput = true,
97+
WindowStyle = ProcessWindowStyle.Hidden,
98+
CreateNoWindow = true,
99+
ErrorDialog = false,
100+
WorkingDirectory = workingDirectory,
101+
FileName = exe,
102+
Arguments = args
103+
};
104+
foreach (var environmentalVariable in environmentalVariables)
105+
{
106+
if (psi.EnvironmentVariables.ContainsKey(environmentalVariable.Key))
107+
{
108+
psi.EnvironmentVariables[environmentalVariable.Key] = environmentalVariable.Value;
109+
}
110+
else
111+
{
112+
psi.EnvironmentVariables.Add(environmentalVariable.Key, environmentalVariable.Value);
113+
}
114+
if (psi.EnvironmentVariables.ContainsKey(environmentalVariable.Key) && environmentalVariable.Value == null)
115+
{
116+
psi.EnvironmentVariables.Remove(environmentalVariable.Key);
117+
}
118+
}
119+
120+
using var process = Start(psi);
121+
using var mreOut = new ManualResetEvent(false);
122+
using var mreErr = new ManualResetEvent(false);
123+
process.EnableRaisingEvents = true;
124+
process.OutputDataReceived += (_, e) =>
125+
{
126+
// ReSharper disable once AccessToDisposedClosure
127+
if (e.Data == null)
128+
mreOut.Set();
129+
else
130+
output(e.Data);
131+
};
132+
process.BeginOutputReadLine();
133+
process.ErrorDataReceived += (_, e) =>
134+
{
135+
// ReSharper disable once AccessToDisposedClosure
136+
if (e.Data == null)
137+
mreErr.Set();
138+
else
139+
errorOutput(e.Data);
140+
};
141+
process.BeginErrorReadLine();
142+
143+
string line;
144+
while (input != null && null != (line = input.ReadLine()))
145+
process.StandardInput.WriteLine(line);
146+
147+
process.StandardInput.Close();
148+
process.WaitForExit();
149+
150+
mreOut.WaitOne();
151+
mreErr.WaitOne();
152+
153+
return process.ExitCode;
154+
}
155+
156+
/// <summary>
157+
/// System error codes.
158+
/// See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382.aspx
159+
/// </summary>
160+
private enum NativeErrorCode
161+
{
162+
Success = 0x0,
163+
FileNotFound = 0x2,
164+
PathNotFound = 0x3
165+
}
166+
167+
[Flags]
168+
public enum ErrorModes
169+
{
170+
Default = 0x0,
171+
FailCriticalErrors = 0x1,
172+
NoGpFaultErrorBox = 0x2,
173+
NoAlignmentFaultExcept = 0x4,
174+
NoOpenFileErrorBox = 0x8000
175+
}
176+
177+
private struct ChangeErrorMode : IDisposable
178+
{
179+
private readonly int oldMode;
180+
181+
public ChangeErrorMode(ErrorModes mode)
182+
{
183+
try
184+
{
185+
oldMode = SetErrorMode((int)mode);
186+
}
187+
catch (Exception ex) when (ex is EntryPointNotFoundException || ex is DllNotFoundException)
188+
{
189+
oldMode = (int)mode;
190+
}
191+
}
192+
193+
194+
void IDisposable.Dispose()
195+
{
196+
try
197+
{
198+
SetErrorMode(oldMode);
199+
}
200+
catch (Exception ex) when (ex is EntryPointNotFoundException || ex is DllNotFoundException)
201+
{
202+
// NOTE: Mono doesn't support DllImport("kernel32.dll") and its SetErrorMode method, obviously. @asbjornu
203+
}
204+
}
205+
206+
[DllImport("kernel32.dll")]
207+
private static extern int SetErrorMode(int newMode);
208+
}
209+
}
210+
}

src/GitVersion.App.Tests/PullRequestInBuildAgentTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ private static async Task VerifyPullRequestVersionIsCalculatedProperly(string pu
136136
{
137137
using var fixture = new EmptyRepositoryFixture();
138138
var remoteRepositoryPath = PathHelper.GetTempPath();
139-
Repository.Init(remoteRepositoryPath);
139+
RepositoryFixtureBase.Init(remoteRepositoryPath);
140140
using (var remoteRepository = new Repository(remoteRepositoryPath))
141141
{
142142
remoteRepository.Config.Set("user.name", "Test");

0 commit comments

Comments
 (0)