Accessing GitHub using REST and C#
Some time ago I created a GitStat app and described it in this post. To do that I used the libgit2sharp library, which I also planned to use for git plugin for TeamScreen. Unfortunately, at the time I’m writing this post, there isn’t the libgit2sharp version for .NET Core. I needed alternate approach so I decided to go for accessing GitHub repository via its REST API. I wanted to have general solution, but it’s just not possible at this time 🙁
Plugin creation is described in previous posts and I’m gonna use an excellent RestEase library for accessing GitHub’s REST API. Description why RestEase is fun and how to use it you can find here. I want to display recent commits and also some basic statistics, an interface for RestEase shows what’s exactly I’m gonna need from GitHub:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
using System.Net.Http.Headers; using System.Threading.Tasks; using RestEase; namespace TeamScreen.Plugin.Git.Integration { [Header("User-Agent", "TeamScreen")]//GitHub requires user-agent public interface IGitHubClient { [Header("Authorization")] AuthenticationHeaderValue Authorization { get; set; } [Get("/repos/{owner}/{repo}/commits")] Task<GetCommitsResponse[]> GetCommitsAsync([Path]string owner, [Path]string repo); [Get("/repos/{owner}/{repo}/branches")] Task<GetBranchesResponse[]> GetBranchesAsync([Path]string owner, [Path]string repo); [Get("/repos/{owner}/{repo}/tags")] Task<GetTagsResponse[]> GetTagsAsync([Path]string owner, [Path]string repo); [Get("/repos/{owner}/{repo}/collaborators")] Task<GetTagsResponse[]> GetCollaboratorsAsync([Path]string owner, [Path]string repo); } } |
Having clients interface, next I create GitHubService, that uses it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
using System; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using RestEase; namespace TeamScreen.Plugin.Git.Integration { public interface IGitHubService { Task<GetCommitsResponse[]> GetCommits(string username, string password, string owner, string repo); Task<GetBranchesResponse[]> GetBranches(string username, string password, string owner, string repo); Task<GetTagsResponse[]> GetTags(string username, string password, string owner, string repo); Task<GetTagsResponse[]> GetCollaborators(string username, string password, string owner, string repo); } public class GitHubService : IGitHubService { private const string GitHubApiPath = "https://api.github.com/"; public async Task<GetCommitsResponse[]> GetCommits(string username, string password, string owner, string repo) { var api = CreateApi(username, password); return await api.GetCommitsAsync(owner, repo); } public async Task<GetBranchesResponse[]> GetBranches(string username, string password, string owner, string repo) { var api = CreateApi(username, password); return await api.GetBranchesAsync(owner, repo); } public async Task<GetTagsResponse[]> GetTags(string username, string password, string owner, string repo) { var api = CreateApi(username, password); return await api.GetTagsAsync(owner, repo); } public async Task<GetTagsResponse[]> GetCollaborators(string username, string password, string owner, string repo) { var api = CreateApi(username, password); return await api.GetCollaboratorsAsync(owner, repo); } private IGitHubClient CreateApi(string username, string password) { var api = RestClient.For<IGitHubClient>(GitHubApiPath); var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}")); api.Authorization = new AuthenticationHeaderValue("Basic", credentials); return api; } } } |
Next, we need a controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using TeamScreen.Data.Services; using TeamScreen.Plugin.Git.Integration; using TeamScreen.Plugin.Git.Mapping; using TeamScreen.Plugin.Git.Models; namespace TeamScreen.Plugin.Git.Controllers { public class GitController : Controller { private readonly ISettingsService _settingsService; private readonly IGitHubService _gitHubService; private readonly IGitMapper _gitMapper; public GitController(ISettingsService settingsService, IGitHubService gitHubService, IGitMapper gitMapper) { _settingsService = settingsService; _gitHubService = gitHubService; _gitMapper = gitMapper; } public async Task<PartialViewResult> Content() { var settings = await _settingsService.Get<GitSettings>(Const.PluginName); var commits = await _gitHubService.GetCommits(settings.Username, settings.Password, settings.Owner, settings.Repository); var branches = await _gitHubService.GetBranches(settings.Username, settings.Password, settings.Owner, settings.Repository); var tags = await _gitHubService.GetTags(settings.Username, settings.Password, settings.Owner, settings.Repository); var collaborators = await _gitHubService.GetCollaborators(settings.Username, settings.Password, settings.Owner, settings.Repository); var model = new GitModel { RepositoryName = settings.Repository, Commits = _gitMapper.MapCommits(commits), NumberOfTodaysCommits = _gitMapper.GetNumberOfTodaysCommits(commits), BranchesCount = branches.Length, TagsCount = tags.Length, CollaboratorsCount = collaborators.Length }; return PartialView(model); } public PartialViewResult Settings() { return PartialView(); } public async Task<JsonResult> GetSettings() { var settings = await _settingsService.Get<GitSettings>(Const.PluginName); return Json(settings); } [HttpPost] public async Task SaveSettings([FromBody]GitSettings settings) { await _settingsService.Set(Const.PluginName, settings); } } } |
The controller uses GitHubService to get all needed information, returns it then to the view:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
@model TeamScreen.Plugin.Git.Models.GitModel <style> .commit { height: 6em; } .commit img { width: 4.5em; margin-top: -1.8em; } </style> <h1>@Model.RepositoryName repository</h1> <div class="container"> <div class="row"> <div class="col-xs-6"> <h2>Recent commits:</h2> @foreach (var commit in Model.Commits) { <div class="commit clearfix"> <h4>@commit.Message</h4> @commit.Date <img class="pull-right" src="@Url.Action("GetByEmail", "Photo", new {email = commit.AuthorEmail})" /> </div> } </div> <div class="col-xs-6"> <h2>Statistics:</h2> <h4>Number of commits today: @Model.NumberOfTodaysCommits</h4> <h4>Number of collaborators: @Model.CollaboratorsCount</h4> <h4>Number of branches: @Model.BranchesCount</h4> <h4>Number of tags: @Model.TagsCount</h4> </div> </div> </div> |
All that code produces this screen:
I skip mapping and settings part because they’re very similar to what I described in previous posts. As you can see, having established plugin architecture pays off and adding new plugins is fast and straightforward. Full source code is available on GitHub. Thanks for reading and see you next time!
One thought on “Accessing GitHub using REST and C#”