go-githubのClientをいい感じに組み立ててインスタンスを生成するだけのgo-github-clientを作った

GitHubGitHub Actionsが好きで、いろいろツールを作ったりするのですが、毎回毎回go-githubのClientのインスタンス生成のために何行かコードを書いています。

最初の頃は GITHUB_TOKEN のことだけを考えていていたのが、その後GitHub Enterpriseのエンドポイントも考えるようになり、GitHub Actionsの登場からはActions上の環境変数をうまく使いたくもなり、GitHub CLI extensionがでてきてからは、GH_* という環境変数も考慮する必要がでてきています。

その都度過去のツールのコードをまるっとコピペしつつもgo-githubのClientインスタンス生成コードは変わってきています。

また、go-githubはセマンティックバージョニングを採用している(?)のか、既にv39まできています。 go-githubのClientを引数に受け取るような外部パッケージがあったとき、その外部パッケージが採用しているgo-githubのメジャーバージョンに合わせないといけないのも苦でした。

毎回コピペコードを書いたり、過去ツールの実装を直したりするのも嫌になってきたので、go-github-clientとしてコード片をパッケージ化しました。

github.com

go-github-client

使い方は go-github のメジャーバージョンに合わせて go-github-client/[VERSION]/factory をimportして使うだけです。

package main

import (
    "context"
    "fmt"

    "github.com/k1LoW/go-github-client/v39/factory"
)

func main() {
    ctx := context.Background()
    c, _ := factory.NewGithubClient()
    u, _, _ := c.Users.Get(ctx, "k1LoW")
    fmt.Printf("%s\n", u.GetLocation())
}

factory.NewGithubClient() 内で、環境変数からトークンやエンドポイントの解決をし生成したClientインスタンスを返します。

また、Functional Option Patternを採用しているので、外部からトークンやエンドポイントなどを差し込むことも可能です。

例えば、go-githubをモック化したい場合は、 *http.Client を外部から差し込むことで解決します。

package main

import (
    "context"
    "testing"

    "github.com/google/go-github/v39/github"
    "github.com/k1LoW/go-github-client/v39/factory"
    "github.com/migueleliasweb/go-github-mock/src/mock"
)

func TestUsingMock(t *testing.T) {
    mockedHTTPClient := mock.NewMockedHTTPClient(
        mock.WithRequestMatch(
            mock.GetUsersByUsername,
            github.User{
                Name: github.String("foobar"),
            },
        ),
    )
    c, err := factory.NewGithubClient(factory.HTTPClient(mockedHTTPClient))
    if err != nil {
        t.Fatal(err)
    }

    ctx := context.Background()
    user, _, err := c.Users.Get(ctx, "myuser")
    if err != nil {
        t.Fatal(err)
    }
    got := user.GetName()
    if want := "foobar"; got != want {
        t.Errorf("got %v\nwant %v", got, want)
    }
}

バージョニング

バージョニングは少し特殊です。

このgo-github-clientパッケージ自体がgo-githubのClientを生成するだけのものなので、基本的にgo-githubバージョンと合わせてタグやディレクトリを切っています。

ただ、go-github-client自体の機能追加もあるので、それにはパッチバージョンに加算することで対応します。

表で表すと以下のような感じです。

バージョン 構成
Major google/go-github のmajorバージョン
Minor google/go-github のminorバージョン
Patch google/go-github のpatchバージョンにk1LoW/go-github-clientの更新を加算

まあちょっとひどいですが、利便性を考えて割り切ります。

というわけで

ただのコード片ですが、これからもGitHub APIを叩くツールや実装は作りそうなので、個人的にはこれを使っていこうかと思っています。

そういえば昔もawsecretsというgemを作ったりしていて、成長していないなーなどと思いました。