How to Git Fetch <remote> using libgit2sharp? - libgit2sharp

My existing Fetch method looks like this.
public void Fetch(string remote) => CommandLine.Run($"git fetch {remote}", _repoFolder);
I would like to implement the same feature using libgit2sharp.
This is what I have came up with:
public void Fetch(string remote)
{
var repo = new Repository(_folder);
var options = new FetchOptions();
options.Prune = true;
options.TagFetchMode = TagFetchMode.Auto;
var refSpecs = $"+refs/heads/*:refs/remotes/{remote}/*";
Commands.Fetch(repo, remote, new [] {refSpecs}, options, "Fetching remote");
}
However this fails with the following error message:
System.InvalidOperationException: 'authentication cancelled'
I have also tried with the libgit2sharp-ssh package, where the result is error code 401 (unathorized client).
I presume the git command line tool works because it knows how to authorize the access (since there is already a remote). How can I achieve the same using libgit2sharp?

Have you tried something like
using(var repo = new Repository(_folder))
{
var options = new FetchOptions();
options.Prune = true;
options.TagFetchMode = TagFetchMode.Auto;
options.CredentialsProvider = new CredentialsHandler(
(url, usernameFromUrl, types) =>
new UsernamePasswordCredentials()
{
Username = "username",
Password = "password"
});
var remote = repo.Network.Remotes["origin"];
var msg = "Fetching remote";
var refSpecs = remote.FetchRefSpecs.Select(x => x.Specification);
Commands.Fetch(repo, remote.Name, refSpecs, options, msg);
}

Related

How to perform git rebase using LibGit2Sharp?

I am writing a program that manipulates a git repo using the LibGit2Sharp library. One of the operations that I need to perform is a rebase to incorporate changes made to the master into a branch. How do I perform a git rebase master command using LibGit2Sharp? I haven't been able to find any examples of this.
What about something like
using(var repo = new Repository("path"))
{
var id = new Identity("name", "email");
var opt = new RebaseOptions();
var rebaseResult = repo.Rebase.Start(
featureBranch,
masterBranch,
null,
id,
opt);
}
The following is based on dontbyteme but will do a git pull --rebase:
using var gitRepo = new LibGit2Sharp.Repository(r.Path);
var remote = r.Network.Remotes["origin"];
var refSpecs = remote.FetchRefSpecs.Select(x => x.Specification);
Commands.Fetch(r, remote.Name, refSpecs, new FetchOptions { Prune = true }, string.Empty);
var id = new Identity("name", "email");
var opt = new RebaseOptions();
var rebaseResult = gitRepo.Rebase.Start(
branch: gitRepo.Head,
upstream: gitRepo.Head.TrackedBranch,
onto: null,
id,
opt
);

LibGit2Sharp-SSH "Failed to start SSH session: Unable to exchange encryption keys"

I'm using the current version of LibGit2Sharp-SSH from https://github.com/leobuskin/libgit2sharp-ssh
I generated a SSH private and public key using OpenSSH.
I set up an OpenSSH Server, and am able to use Git Bash to Clone/Push etc. using SSH.
I'm having difficulties Cloning a repository using the SSH protocol through LibGit2Sharp.
I've went through all the similar questions and tried all the answers without any luck.
public CloneOptions cloningSSHAuthentication(string username, string path_to_public_key_file, string path_to_private_key_file)
{
CloneOptions options = new CloneOptions();
SshUserKeyCredentials credentials = new SshUserKeyCredentials();
credentials.Username = username;
credentials.PublicKey = path_to_public_key_file;
credentials.PrivateKey = path_to_private_key_file;
credentials.Passphrase = "passphrase";
options.CredentialsProvider = new LibGit2Sharp.Handlers.CredentialsHandler((url, usernameFromUrl, types) => credentials);
return options;
}
public void CloneRepo(string remotePath, string localPath)
{
var sshDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ssh");
var PublicKey = Path.Combine(sshDir, "id_rsa.pub");
var PrivateKey = Path.Combine(sshDir, "id_rsa");
CloneOptions options = cloningSSHAuthentication("UserName", PublicKey, PrivateKey);
Repository.Clone(remotePath, localPath, options);
}
I get a "Failed to start SSH session: Unable to exchange encryption keys" exception.
Has anyone had a similar experience or know what I could possibly be missing?

Sample Webapi to trigger TFS rest services & post HTTP calls

I have been working on a requirement, i.e. when a bug is created/inprogress in TFS post a HTTP call to Slack (third party collaboration tool).
When a bug is closed post one more HTTP call to Slack.
I had implemented TFS server side plugin, unfortunately we don't have complete access to TFS and cannot implement. So, planning to implement Webapi and host it (say in Docker container) and whenever bug created / closed event happens in TFS it should post HTTP call.
I have created a simple console app with a method and it's working fine.
any sample code or thoughts to convert it to web api?
if I host, can it monitor TFS events and posts some HTTP calls?
public class GetWI
{
static void Main(string[] args)
{
GetWI ex = new GetWI();
ex.GetWorkItemsByWiql();
}
public void GetWorkItemsByWiql()
{
string _personalAccessToken = "xxxx";
string _credentials = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", _personalAccessToken)));
//this is needed because we want to create a project scoped query
string project = "Agileportfolio";
//create wiql object
var wiql = new
{
query = "Select [State], [Title] " +
"From WorkItems " +
"Where [Work Item Type] = 'Bug' " +
"And [System.TeamProject] = '" + project + "' " +
"And [System.State] = 'New' " +
"Order By [State] Asc, [Changed Date] Desc"
};
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://test.visualstudio.com");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", _credentials);
//serialize the wiql object into a json string
var postValue = new StringContent(JsonConvert.SerializeObject(wiql), Encoding.UTF8, "application/json"); //mediaType needs to be application/json for a post call
var method = new HttpMethod("POST");
var httpRequestMessage = new HttpRequestMessage(method, "https://abrahamdhanyaraj.visualstudio.com/_apis/wit/wiql?api-version=2.2") { Content = postValue };
var httpResponseMessage = client.SendAsync(httpRequestMessage).Result;
if (httpResponseMessage.IsSuccessStatusCode)
{
WorkItemQueryResult workItemQueryResult = httpResponseMessage.Content.ReadAsAsync<WorkItemQueryResult>().Result;
//now that we have a bunch of work items, build a list of id's so we can get details
var builder = new System.Text.StringBuilder();
foreach (var item in workItemQueryResult.WorkItems)
{
builder.Append(item.Id.ToString()).Append(",");
}
//clean up string of id's
string ids = builder.ToString().TrimEnd(new char[] { ',' });
HttpResponseMessage getWorkItemsHttpResponse = client.GetAsync("_apis/wit/workitems?ids=" + ids + "&fields=System.Id,System.Title,System.State&asOf=" + workItemQueryResult.AsOf + "&api-version=2.2").Result;
if (getWorkItemsHttpResponse.IsSuccessStatusCode)
{
var result = getWorkItemsHttpResponse.Content.ReadAsStringAsync().Result;
//Read title
}
}
// Create Channel
string name = "xyzz3";
var payload = new
{
token = "xoxp-291239704800-292962676087-297314229698-a80e720d98e443c8afb0c4cb2c09e745",
name = "xyzz3",
};
var serializedPayload = JsonConvert.SerializeObject(payload);
var response = client.PostAsync("https://slack.com/api/channels.create" + "?token=test&name=" + name + "&pretty=1",
new StringContent(serializedPayload, Encoding.UTF8, "application/json")).Result;
if (response.IsSuccessStatusCode)
{
dynamic content = JsonConvert.DeserializeObject(
response.Content.ReadAsStringAsync()
.Result);
}
}
}
I use wcf service to listen events from TFS. You may find my project here: https://github.com/ashamrai/tfevents
For wcf service:
Update your ServiceName.svc file and add:
Factory="System.ServiceModel.Activation.WebServiceHostFactory"
Create web method to use json:
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
void WorkItemChangedEvent(Stream EventData);
Convert stream with Newtonsoft.Json to get information about event and work item:
StreamReader _reader = new StreamReader(pEventData, Encoding.UTF8);
string _eventStr = _reader.ReadToEnd();
WorkItemEventCore _wieventcorre = JsonConvert.DeserializeObject(_eventStr);
Then you have to create the subscription with url "http://host:port/service.svc/webmethod": https://learn.microsoft.com/en-us/vsts/service-hooks/services/webhooks
Instead of using a query and manually polling Visual Studio Team Services (VSTS), you can use a concept called WebHooks. You configure a WebHook in VSTS to listen for events and send these to a public endpoint. One event type is for Work Items. The endpoint can be any type of public endpoint, for example an Azure Function.
If the only thing you want to do is post the events to Slack, it's even easier because that's a standard integration point: Slack with VSTS.
This is much easier then using a server side plugin or writing your own Web API.

How to provide credentials to Fetch() and Pul() methods?

I'm looking for a nice clean example of how to do a pull using lidgit2sharp. I took the example here which does a fetch, but the reference to Credentials is throwing an exception.
using (var repo = new Repository(workingDir, null))
{
Remote remote = repo.Network.Remotes.Add("master", repoUrl);
repo.Network.Fetch(remote,
{
Credentials credentials = new Credentials
{
Username = "username",
Password = "password"
}
});
}
The exception is Cannot create an instance of the abstract class or
interface 'LibGit2Sharp.Credentials'
It's telling you in the error: Credentials is an abstract class, interface, whatever.
Try this:
Credentials credentials = new UsernamePasswordCredentials()
{
Username = "username",
Password = "password"
}

How can one supply credentials during a Fetch call?

We're not talking about SSH since it's not yet implemented, but how can I supply credentials for the repository before I perform a fetch via HTTP/HTTPS? There doesn't seem to be a parameter for a Credentials instance, and nothing when constructing a Repository instance for storing credentials.
Within the FetchFixture.cs file, there is a Fetch() test using credentials:
[SkippableFact]
public void CanFetchIntoAnEmptyRepositoryWithCredentials()
{
InconclusiveIf(() => string.IsNullOrEmpty(Constants.PrivateRepoUrl),
"Populate Constants.PrivateRepo* to run this test");
string repoPath = InitNewRepository();
using (var repo = new Repository(repoPath))
{
Remote remote = repo.Network.Remotes.Add(remoteName, Constants.PrivateRepoUrl);
// Perform the actual fetch
repo.Network.Fetch(remote, new FetchOptions
{
Credentials = new Credentials
{
Username = Constants.PrivateRepoUsername,
Password = Constants.PrivateRepoPassword
}
});
}
}

Resources