GitHubはAPIが公開されていて、アプリケーションから操作することが可能です。
アプリケーションからAPI操作をするためのライブラリである、Octokitも用意されています。konoOctokithagennzai.NET, Obj-C, Ruby用のライブラリが用意されていて、今回は.NET版のOctokit.netを使用して、C#からGitHubを操作するための触りを紹介したいと思います。
Octokit.netのインストール
NuGetでインストールします。
PM> Install-Package Octokit
アクセスと認証
アプリケーションからgithubにアクセスするにはoctokitのGitHubClientのオブジェクトを作成する必要があります。
var github = new GitHubClient(new ProductHeaderValue("IshisakaSample"));
上が、認証もProxyも無い一番簡単な例で、GitHubClientのコンストラクタ引数にアプリケーション名を入れたProductHeaderValueのオブジェクトを渡してあげます。これで基本的にGitHubへのアクセスが可能になります。
プライベートリポジトリへのアクセスやIssueの投稿などをする場合にはユーザー認証が必要になるので、以下のように、Basic認証のCledentialsオブジェクトをつくり、先ほどのProductHeaderValueのオブジェクトとあわせて、GitHubClientのコンストラクタに渡します。
public async void AuthenticationSample(string password)
{
// Basic認証のオブジェクトを作成する
// OAuthのTokenを引数に与えても良い
var credential = new Credentials("ishisaka", password);
// 認証付きでGutHUbのクライアントを作成
var github = new GitHubClient(
new ProductHeaderValue("IshisakaSample"),
new InMemoryCredentialStore(credential));
}
}
5行目でBasic認証のCledentialsオブジェクトを作成するためにコンスタ久谷ユーザー名とパスワードを渡しています。OAuthを使ってアクセスしたい場合には、先にOAuthのトークンを所得しておき、Cledentialsのコンストラクタにそのトークンをstringで渡します。
8行目でGitHubClientのオブジェクトを作っていますが、第二引数にICredentialStoreを持ったオブジェクトを与える必要があるので、ここではOctocat.netが持っているInMemoryCredentialStoreを使っています。たとえば、ファイルからであるとか、レジストリに認証情報を保存するような場合には自分でIcredentialStoreを持ったクラスを作成して使用することも出来ると思います。
Proxyを経由したアクセスが必要な場合にはもう少し複雑になります。
先ほどまでのやり方では、GitHubClientがコンストラクタの中で自動生成していたConnectionオブジェクトを外側で作成してからGitHubClientのオブジェクトを作成する必要があります。
protected async void UseProxySample(string password)
{
var proxy = new WebProxy("Proxy Address");
// IE(System)のProxy設定を使用する場合には上に変わって以下のようにします。
////var proxy = WebRequest.GetSystemWebProxy();
// 認証Proxyを使用している場合でNTLM認証(システムの認証情報)を使用する場合には以下のように指定する
proxy.Credentials = CredentialCache.DefaultCredentials;
// Basicユーザー認証を使用するProxyでは上に変わり下のように指定します。
////proxy.Credentials = new NetworkCredential("User", "password");
var client = new HttpClientAdapter(proxy);
var credentialStore = new InMemoryCredentialStore(new Credentials("UserName", password));
var connection = new Connection(
new ProductHeaderValue("IshiakaApps"),
GitHubClient.GitHubApiUrl,
credentialStore,
client,
new SimpleJsonSerializer());
var github = new GitHubClient(connection);
// next something else.
}
手順的なところは上のコード内のコメント後確認いただきたいのですが、IProxyを持つオブジェクトを作成し、必要な設定をつくったら、それを引数にOcotkitのHttpClientAdapterのオブジェクトを作成、認証に必要なICredetialStoreオブジェクトを作成して、それらを引数としてConnectionのオブジェクトを作成します。
データアクセス
ここではIssueへのアクセスを試みます。
Octokit.netのデータ取得、投稿、変更の各メソッドは全て非同期になっているので、それを前提にコード書く必要があります。
とは言っても、Linqとasync/awaitが有るので、そんなに難しくはありません。
以下は特定のレポジトリかIssue全体を取得してコンソールに表示、ユーザーのアバタ画像を保存しています。
ソースを見ていただければ特に説明もいらないかと思います。
public async void GetIssues()
{
// クライアントを作成する。公開レポジトリなら認証は必要なし
var github = new GitHubClient(new ProductHeaderValue("IshisakaSample"));
// イシューを取得する。オーナー名、レポジトリ名を引数に
IReadOnlyList issues = await github.Issue.GetForRepository("ishisaka", "nodeintellisense");
foreach (Issue issue in issues)
{
Console.WriteLine("Number:\t{0}", issue.Number);
Console.WriteLine("Title:\t{0}", issue.Title);
Console.WriteLine("Date:\t{0}", issue.CreatedAt);
Console.WriteLine("Body: \r\n{0}", issue.Body);
Console.WriteLine("User:\t{0}", issue.User.Login);
Console.WriteLine("--------");
// ユーザーのアバター画像を取得
var avatorUrl = new Uri(issue.User.AvatarUrl);
var client = new WebClient();
string downloadPath = @"d:\temp\" + issue.User.Login + ".png";
await
client.DownloadFileTaskAsync(avatorUrl, downloadPath)
.ContinueWith(t => Console.WriteLine(downloadPath + " download Complte."));
}
}
IreadOnlyListで結果を返してくるのが結構気に入らない感じもしますが、ものすごく簡単です。
また、プロパティ名等でよくわからないときにはGitHub APIのドキュメントを読むのが良いと思います。
では、追加と更新を見てみましょう。
これもコードを見ていただければわかると思います。
public async void PutIssues(string password)
{
Console.WriteLine("レポジトリにIssueを追加する");
var credential = new Credentials("ishisaka", password);
var github = new GitHubClient(
new ProductHeaderValue("IhsisakaSample"),
new InMemoryCredentialStore(credential));
var newIssue = new NewIssue("サンプルイシュー" + DateTime.Now.ToShortTimeString())
{
Body = "にほんごてきすと",
// 担当ユーザーの割り当てをする場合にはAssigneeプロパティに有効なユーザー名を指定
Assignee = "ishisaka"
};
// Issueを新規追加。追加されたIssueが戻ってくる
var ret = await github.Issue.Create("ishisaka", "juzshizuoka", newIssue);
Console.WriteLine("追加されたIssue");
Console.WriteLine("Number:\t{0}", ret.Number);
Console.WriteLine("Title:\t{0}", ret.Title);
Console.WriteLine("Date:\t{0}", ret.CreatedAt);
Console.WriteLine("Body: \r\n{0}", ret.Body);
Console.WriteLine("User:\t{0}", ret.User.Login);
Console.WriteLine("--------");
// 編集
// 編集 正直いちいちIssueUpdate作るのがメンドイ
var issuesUpdate = new IssueUpdate { Title = ret.Title, Body = ret.Body + "\r\n編集しました。" };
var retUpdate = await github.Issue.Update("ishisaka", "juzshizuoka", ret.Number, issuesUpdate);
// 編集されたIssue
Console.WriteLine("編集されたIssue");
Console.WriteLine("Number:\t{0}", retUpdate.Number);
Console.WriteLine("Title:\t{0}", retUpdate.Title);
Console.WriteLine("Date:\t{0}", retUpdate.CreatedAt);
Console.WriteLine("Body: \r\n{0}", retUpdate.Body);
Console.WriteLine("User:\t{0}", retUpdate.User.Login);
Console.WriteLine("--------");
}
もうおわかりとは思いますが、同じIssueなのに、取得時、作成時、更新時で別々のクラスを使用して、別のインスタンスを作る必要があって面倒です。
ただ、これは元々のGitHub APIのJSONオブジェクトがやはりそれぞれで異なっているため、APIにあわせて作成されているのだろうと考えます。
Reactive!
よく訓練されたC#使いは今までのコードを見てくると、何となくおしりのあたりがむずむずしてくると言うか、そのForEachを.Subscribeに変えたくなってくると思います。
Octokit.netにはReactive Extensionsを使用したライブラリがOctokit.Reactiveの名前空間で用意されており、オブザーバーパターンでというか、Rxできます。
以下は、Reactiveでデータ取得する場合のコードです。
public void GetIssues()
{
// クライアントを作成する。公開レポジトリなら認証は必要なし
var github = new GitHubClient(new ProductHeaderValue("IshisakaSample"));
// ObservableIssuesClientを作成する
var issueObserver = new ObservableIssuesClient(github);
// レポジトリのIssueを取得して、表示する。Rxを使えばこんなに簡潔に書けます。
issueObserver.GetForRepository("ishisaka", "nodeintellisense").Subscribe(
i =>
{
Console.WriteLine("Number:\t{0}", i.Number);
Console.WriteLine("Title:\t{0}", i.Title);
Console.WriteLine("Date:\t{0}", i.CreatedAt);
Console.WriteLine("Body: \r\n{0}", i.Body);
Console.WriteLine("User:\t{0}", i.User.Login);
Console.WriteLine("--------");
});
}
だいぶすっきりしました。
Rxするには、データのアクセスに目的に合わせたObservableで始まるクラスのコンストラクタにGitHubClientのインスタンスを渡し、目的の操作を呼んでSubscribeです。
以下は追加の例です。
public void PutIssue(string password)
{
Console.WriteLine("レポジトリにIssueを追加する");
var credential = new Credentials("ishisaka", password);
var github = new GitHubClient(
new ProductHeaderValue("IshisakaSample"),
new InMemoryCredentialStore(credential));
var newIssue = new NewIssue("サンプルイシュー" + DateTime.Now.ToShortTimeString())
{
Body = "にほんごてきすと",
// 担当ユーザーの割り当てをする場合にはAssigneeプロパティに有効なユーザー名を指定
Assignee = "ishisaka"
};
var issueObserver = new ObservableIssuesClient(github);
issueObserver.Create("ishisaka", "juzshizuoka", newIssue).Subscribe(
ret =>
{
Console.WriteLine("追加されたIssue");
Console.WriteLine("Number:\t{0}", ret.Number);
Console.WriteLine("Title:\t{0}", ret.Title);
Console.WriteLine("Date:\t{0}", ret.CreatedAt);
Console.WriteLine("Body: \r\n{0}", ret.Body);
Console.WriteLine("User:\t{0}", ret.User.Login);
Console.WriteLine("--------");
});
}
いやぁいいですねぇ。
##まとめ
- GitHubが.NET向けにOctokit.netと言うGitHub API用のアクセスライブラリを用意していて、Nugetでインストールできます.
- 非同期のアクセスライブラリと、Rxのアクセスライブラリが用意されていて、使用方法自体はGitHub APIを参照すればそれほど難しくはありません。Reactiveの方を使えばいいんじゃないかな。
- ここまで書けば誰かVSのアドインを作ってくれるかな? |д゚)チラッ
全体コードはGitHubで公開しています。
コメント
RT @ishisaka: http://t.co/o1yoMwZ7GxによるGitHubへのアクセス http://t.co/ioqId51rmQ