Run git commands from a C# function - c#

How can my C# code run git commands when it detects changes in tracked file? I am writing a VisualStudio/C# console project for this purpose.
I am new to the the .NET environment and currently working on integrating automated GIT commits to a folder. I need to automatically commit any change/add/delete on a known folder and push that to a git remote. Any guidance appreciated. Thank you.
Here is what I have and the last one is the one I need some guidance with:
Git repository initially set up on folder with proper ignore file (done).
I am using C# FileSystemWatcher to catch any changes on said folder (done).
Once my project detects a change it needs to commit and push those changes (pending).
Tentative commands the project needs to run:
git add -A
git commit "explanations_of_changes"
git push our_remote
NOTE: This code (with no user interaction) will be the only entity committing to this repo so I am not worried about conflicts and believe this flow will work.

I realize this is an old question but I wanted to add the solution I recently came across to help those in the future.
The PowerShell class provides an easy way to interact with git. This is part of the System.Management.Automation namespace in .NET. Note that System.Management.Automation.dll is available via NuGet.
string directory = ""; // directory of the git repository
using (PowerShell powershell = PowerShell.Create()) {
// this changes from the user folder that PowerShell starts up with to your git repository
powershell.AddScript($"cd {directory}");
powershell.AddScript(#"git init");
powershell.AddScript(#"git add *");
powershell.AddScript(#"git commit -m 'git commit from PowerShell in C#'");
powershell.AddScript(#"git push");
Collection<PSObject> results = powershell.Invoke();
}
In my opinion this is cleaner and nicer than using the Process.Start() approach. You can modify this to your specfic needs by editing the scripts that are added to the powershell object.
As commented by #ArtemIllarionov, powershell.Invoke() does not return errors but the Streams property has output information. Specifically powerShell.Streams.Error for errors.

If you want to do it in C#, you can call the external git command by Process.Start when you detect file change
string gitCommand = "git";
string gitAddArgument = #"add -A";
string gitCommitArgument = #"commit ""explanations_of_changes""";
string gitPushArgument = #"push our_remote";
Process.Start(gitCommand, gitAddArgument);
Process.Start(gitCommand, gitCommitArgument);
Process.Start(gitCommand, gitPushArgument);
Not the best solution but it works in C#

using System.Diagnostics;
using System.Text;
//Console.WriteLine(CommandOutput("git status"));
public static string CommandOutput(string command,
string workingDirectory = null)
{
try
{
ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c " + command);
procStartInfo.RedirectStandardError = procStartInfo.RedirectStandardInput = procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
if (null != workingDirectory)
{
procStartInfo.WorkingDirectory = workingDirectory;
}
Process proc = new Process();
proc.StartInfo = procStartInfo;
proc.Start();
StringBuilder sb = new StringBuilder();
proc.OutputDataReceived += delegate (object sender, DataReceivedEventArgs e)
{
sb.AppendLine(e.Data);
};
proc.ErrorDataReceived += delegate (object sender, DataReceivedEventArgs e)
{
sb.AppendLine(e.Data);
};
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
proc.WaitForExit();
return sb.ToString();
}
catch (Exception objException)
{
return $"Error in command: {command}, {objException.Message}";
}
}

Try LibGit2Sharp, a native implementation of git for .NET:
https://github.com/libgit2/libgit2sharp/

One alternative would be to setup Grunt and TaskRunner with your project.
Grunt should be able to provide the automation of detecting changes to a folder(or folders) in your project and execute the appropriate git commands to commit it.
Task Runner allows you to initialize and run Grunt from within Visual Studio.
The Visual Studio team has indicated that Task Runner is going to become integrated into future releases of Visual Studio, so this could be a long term solution.
Note: It has been mentioned in the comments, but I feel it worth mentioning again that auto-commiting anytime a file is saved to the repository isn't best practice. You want functional / atomic code changes to get pushed in, not simple text changes. Auto-Commit at your own risk.

The Package Manager Console is Powershell console. So you can run your git commands from there.

Related

What is the best way to check PowerShell Execution Policy in C#?

When you run Get-ExecutionPolicy in PowerShell, it gets the effective execution policy. I need to know the best way to get that information in C#. I don't need to know how to change it like many other questions about PowerShell Execution Policy, I just need to know how to get it in C#.
Note:
PowerShell execution policies apply only on Windows.
With respect to Windows, the answer below covers both PowerShell editions.
It can be inferred from the docs that boxdog pointed to in a comment, but to spell it out:
using System;
using System.Management.Automation;
namespace demo
{
class ConsoleApp {
static void Main() {
using (var ps = PowerShell.Create()) {
var effectivePolicy = ps.AddCommand("Get-ExecutionPolicy").Invoke()[0].ToString();
ps.Commands.Clear();
Console.WriteLine("Effective execution policy: " + effectivePolicy);
}
}
}
}
Note:
The above assumes that you're using the PowerShell SDK - see this answer for the appropriate NuGet package to add to your project.
If you're using a PowerShell (Core) 7+ SDK, additional considerations apply:
On Unix-like platforms, execution policies fundamentally do not apply (Unrestricted is reported, though in effect it is Bypass), so the following applies to Windows only:
The LocalMachine scope of any - by definition install-on-demand - PowerShell (Core) 7+ version does not apply; only - if defined - the CurrentUser and GPO-based policies (which preempt the former) do.
On Windows:
In the absence of a relevant execution policy being defined, Restricted is the default, which categorically prevents execution of script files (.ps1).
If your application needs to execute .ps1 files when hosting the PowerShell SDK, for predictable behavior it is best to set the execution policy, for the current process only, as shown in this answer.
The most elegant solution would probably be to get the ExecutionPolicy registry key in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell. For this solution to work, your program needs to be running on the same architecture (x64 or x86) as the operating system it's running on or it won't be able to see the registry key. Code to do this would look something like this:
using Microsoft.Win32
...
string executionPolicy = Registry.GetValue(#"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell", "ExecutionPolicy", null)?.ToString();
If for any reason you can't do the first solution, the second way I would recommend is by using the System.Management.Automation.PowerShell NuGet package. This method would look something like this:
using(var ps = PowerShell.Create()){
ps.AddScript("Get-ExecutionPolicy");
Collection<PSObject> output = ps.Invoke();
Console.WriteLine($"Execution policy is {output[0]}")
}
If you really don't want to add an extra NuGet package to your project, there is another, but quite a bit messier way of doing this using System.Diagnostics.Process and it's output stream. It would look something like this:
var procInfo = new ProcessStartInfo("powershell.exe", "-Command \"Get-ExecutionPolicy\"")
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true
};
var proc = new Process
{
StartInfo = procInfo
};
proc.OutputDataReceived += Proc_OutputDataReceived;
proc.Start();
proc.BeginOutputReadLine();
Console.ReadLine();
...
private static void Proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (!string.IsNullOrWhiteSpace(e.Data))
Console.WriteLine($"Execution policy is {e.Data}");
}

File copy started from aspnet webforms and implemented using batch, pstools and robocopy doesn't work

I have 4 independent servers (not in domain):
IIS, SQL1, SQL2, SQL3
I want to copy a database backup from SQL1 to SQL2 or SQL3 (depending on parameters) by button click on webpage hosted on IIS
I wrote a button click method for that, which is calling batch file located in inetpub folder on IIS
Batch is using pstools to run robocopy on SQL1 which should copy required file to destination server (SQL2 or SQL3)
This solution works if I execute batch directly on IIS (cmd as Administrator) or when I debug it on my local machine, but it doesn't if it is called from the running site.
It even doesn't spend any time between the following lines:
batchProcess.Start();
batchProcess.WaitForExit();
Here is my copy method:
private bool ProcessCopy(string file, string destinationIp)
{
SecureString password = ConvertToSecureString("myPassword");
try
{
string batchPath = Server.MapPath(".") + "\\CopyFile.bat";
string cmd = #"c:\Windows\System32\cmd.exe";
ProcessStartInfo processInfo = new ProcessStartInfo
{
FileName = cmd,
UseShellExecute = false
};
Process batchProcess = new Process {StartInfo = processInfo};
batchProcess.StartInfo.Arguments = $"/C {batchPath} {file} {destinationIp}";
batchProcess.StartInfo.Domain = "";
batchProcess.StartInfo.UserName = "Administrator";
batchProcess.StartInfo.Password = password;
batchProcess.StartInfo.RedirectStandardOutput = true;
batchProcess.StartInfo.RedirectStandardError = true;
batchProcess.StartInfo.CreateNoWindow = true;
batchProcess.Start();
batchProcess.WaitForExit();
string response = batchProcess.StandardOutput.ReadToEnd();
response += batchProcess.StandardError.ReadToEnd();
statusStringAppend($"response: {response}");
return true;
}
catch (Exception ex)
{
statusStringAppend($"Failed: {ex.Message}. {ex.StackTrace}");
}
return false;
}
Batch body is:
#echo off
c:\qa\tools\pstools\psexec64.exe -accepteula -u Administrator -p myPassword \\SourceIP robocopy \\SourceIP\qa\db_backup\ \\%2\qa\db_backup\ %1 /is
My questions are:
1. Why the file was not copied?
2. Is there any better way to get it copied?
CODE UPDATED ACCORDING TO SUGGESTIONS BELOW
My guess is that you never executed pstools as the user that your IIS service is running as before, so the EULA dialog is blocking your execution.
If you remember, you always got a window and needed to press the accept button when running any sysinternals tool like pstools the first time.
I guess this should work for you:
c:\qa\tools\pstools\psexec64.exe -accepteula -u Administrator -p myPassword \\SourceIP robocopy \\SourceIP\qa\db_backup\ \\%2\qa\db_backup\ %1 /is
[EDIT]
You would most likely have hit this problem later on, anyway it did not work for you, so i have to list what else could be wrong with your code:
starting a .bat file needs cmd.exe as mother process, you cannot just start a .bat file as process directly. Instead you can for example use another method than ProcessStartInfo that spawns the system default script interpreter automatically: Executing Batch File in C#
the process for executing batch files is "cmd.exe", first parameter "/C", second parameter the batch file you are executing
when executing typical commandline tools, you might consider reading the SDTOUT (standard output) of the process you are executing, like this: Capturing console output from a .NET application (C#)

get git command line return value using c#

I want to run git commands from c#. below is the coded I had written and it does execute the git command but I am not able to capture the return value. When I manually run it from command line this is the output I get.
When I run from the program the only thing I get is
Cloning into 'testrep'...
Rest of the info is not capture, but the command is executed successfully.
class Program
{
static void Main(string[] args)
{
ProcessStartInfo startInfo = new ProcessStartInfo("git.exe");
startInfo.UseShellExecute = false;
startInfo.WorkingDirectory = #"D:\testrep";
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
startInfo.Arguments = "clone http://tk1:tk1#localhost/testrep.git";
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
List<string> output = new List<string>();
string lineVal = process.StandardOutput.ReadLine();
while (lineVal != null)
{
output.Add(lineVal);
lineVal = process.StandardOutput.ReadLine();
}
int val = output.Count();
process.WaitForExit();
}
}
From the manual page for git clone:
--progress
Progress status is reported on the standard error stream by default when it is attached to
a terminal, unless -q is specified. This flag forces progress status even if the standard
error stream is not directed to a terminal.
The last three lines in the output when running git clone interactively are sent to standard error, not standard output. They won't show up there when you run the command from your program, however, since it's not an interactive terminal. You could force them to appear, but the output isn't going to be anything usable for a program to parse (lots of \rs to update the progress values).
You are better off not parsing the string output at all, but looking at the integer return value of git clone. If it's nonzero, you had an error (and there will probably be something in standard error that you can show to your user).
Have you tried libgit2sharp? The documentation is not complete, but it is pretty easy to use and there's a nuget package for it. You can always look at the test code to see about usage as well. A simple clone would be like this:
string URL = "http://tk1:tk1#localhost/testrep.git";
string PATH = #"D:\testrep";
Repository.Clone(URL, PATH);
Fetching changes is easy as well:
using (Repository r = new Repository(PATH))
{
Remote remote = r.Network.Remotes["origin"];
r.Network.Fetch(remote, new FetchOptions());
}
Once you call process.WaitForExit() and the process has terminated, you can simply use process.ExitCode which will get you the value that you want.
Your code Looks OK.
this is git problem.
git clone git://git.savannah.gnu.org/wget.git 2> stderr.txt 1> stdout.txt
stderr.txt is empty
stdout.txt:
Cloning into 'wget'...
It looks like git not uses standard console.write() like output you can see it when it writes percentage it's all in one line not like:
10%
25%
60%
100%
process.StandardError.ReadToEnd() + "\n" + process.StandardOutput.ReadToEnd();

Call SVN console client from C#

any ideas how to create a branch from a trunk url in a c# console app.
im trying to create a branching tool, that will create all new branches. for the life of me i have tried almost everything. Sharpsvn has given me no luck.
string command = "cp https://svn:8443/svn/blah/trunk \\ https://svn:8443/svn/blah/branches/newBranch \\";
Process svnBranchProcess = new Process();
svnBranchProcess.StartInfo.FileName = "Svn.exe";
svnBranchProcess.StartInfo.Arguments = command;
svnBranchProcess.StartInfo.UseShellExecute = false;
svnBranchProcess.StartInfo.RedirectStandardOutput = true;
svnBranchProcess.Start();
string output = svnBranchProcess.StandardOutput.ReadToEnd();
svnBranchProcess.WaitForExit();
Console.WriteLine("Output:");
Console.WriteLine(output);
This is the error that i get
svn : Cannot mix repository and working copy sources
Basically i want to be able to create a branch off trunk and then update some externals. why is this such a mission?
thanks for any help :)

How to display C# source code from external file?

For my project I'd like to display C# source code that I get from an external file. All I want to do is to parse that file and if possible display the code with syntax highlighting.
If also possible I'd like to divide the code I read into the various methods.
Where should I start?
I'd recommend AvalonEdit. It's easy to setup and use. Example
xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
<avalonEdit:TextEditor Name="textEditor"
Loaded="textEditor_Loaded"
FontFamily="Consolas"
FontSize="10pt"/>
private void textEditor_Loaded(object sender, RoutedEventArgs e)
{
textEditor.Load(#"C:\MainWindow.xaml.cs");
textEditor.SyntaxHighlighting =
HighlightingManager.Instance.GetDefinition("C#");
}
Example Output
An alternative way is to launch an external tool or app like viewer. For example, in Windows you can use VIM app to open a cs file in read-only and no modification mode:
"C:\Program Files\Vim\vim72\gvim.exe" -R -M C:\test\MyClass.cs
Here are some codes to launch the tool:
public static int StartViewer(string file)
{
string parameters = string.Format("-R -M {0}", file);
ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
psi.FileName = "C:\Program Files\Vim\vim72\gvim.exe";
psi.Arguments = parameters;
Process p = Process.Start(psi);
p.WaitForExit();
return p.ExitCode;
}
I think VIM has CS syntax colorizer, or you can find some better one. It is free and has great search feature. However, VIM may not be good for none-VIM users. This is just an example. You can use other tools if you like to leverage other app strength.
Another take on syntax highlighting.

Categories

Resources