Octokit.NETによるGitHubへのアクセス

GitHubはAPIが公開されていて、アプリケーションから操作することが可能です。

アプリケーションからAPI操作をするためのライブラリである、Octokitも用意されています。konoOctokithagennzai.NET, Obj-C, Ruby用のライブラリが用意されていて、今回は.NET版のOctokit.netを使用して、C#からGitHubを操作するための触りを紹介したいと思います。

GitHub developer

octokit.net

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で公開しています。

https://github.com/ishisaka/OctokitSample1

One thought on “Octokit.NETによるGitHubへのアクセス”

コメントを残す