Pushing Files to GitHub Programmatically

PUBLISHED ON OCT 7, 2013

Recently I had the opportunity to work with GitHub’s API again. This time I was particularily interested in the Repo Contents API. The goal was to be able to publish files from disk or embedded resource (read: stream) directly to a GitHub repo without having to clone the repo somewhere and then issue a git push.

The API seemed (as is always with case with the GitHub API) straightforward and had methods for creating and updating files. So I got to work…

TL;DR - show me the code/installation instructions

In my particular case, I was trying to pull embedded resources out of an assembly, push them to GitHub and then trigger our CI server to run a build and if successful, trigger a deployment.

To get started, I had to think of what would be ideal for me. I came to the conclusion that I needed:

  • an arbitrary array of bytes
  • the target owner/repo
  • a repo-relative path for where the bytes should be stored (file name)

The goal being code that looked like this:

// get the api token from sonewhere...
var service = new ContentService(token);
var file = new DiskFile("Files/content_file.gif");
var target = new FileTarget(owner, repo, file.Name);
service.PushFile(file, target, "pushing file via GitHubPushLib");
view raw result.cs hosted with ❤ by GitHub

I needed to make sure that the app could both create and update a file, so I ended up with the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GitHubPushLib
{
public sealed class ContentService
{
private ContentRepo _repo;
private string _authToken;
public ContentService(string authToken)
: this(authToken, new GitHubContentRepo())
{
}
public ContentService(string authToken, ContentRepo repo = null)
{
Guard.AgainstNullOrEmpty("authToken", authToken);
this._repo = repo;
this._authToken = authToken;
}
public File PushFile(File file, FileTarget target, string message)
{
Guard.AgainstNull("file", file);
Guard.AgainstNull("target", target);
Guard.AgainstNullOrEmpty("message", message);
var existingFile = this._repo.GetFile(this._authToken, target);
if (existingFile != null)
{
// set the hash to the existing one...
file.SHA = existingFile.SHA;
}
return existingFile == null ?
this._repo.CreateFile(this._authToken, file, target, message) :
this._repo.UpdateFile(this._authToken, file, target, message);
}
}
}

The Result

After only a few hours I had a fully tested implementation that I was able to use. I figured that other people might have the same need, so I packaged it up as a NuGet package.

Install-Package GitHubPushLib

If you’re interested, check out the code on GitHub. I’ve setup Travis CI and would love to see some pull requests!

The repo contains a sample app (with instructions) you can use to play around with.

TAGS: API, GITHUB, NUGET