Goのライブラリにはじめてパッチを投げた

はじめに

この記事は、仕事で必要なライブラリにパッチを投げてそれがマージされた時の備忘録です。 今後もパッチを投げる可能性があるのでメモ書きとしてまとめている感じです。

背景

最近、仕事ではもっぱらGoを書いているんですが、ライブラリにパッチを投げるとかそういうことはなく平穏な日々を過ごしてました。 が、数か月前から仕事で大き目な機能改修があり、「さすがにこれは使ってるライブラリを改修しなければならないな」という事態が起きたんですよね……。

まあ、こういう時によくあるのは「Forkしてそれを改修する」か「改修したパッチを投げてマージされるようにする」のどちらかだと思います。

で、今回は後者のパターンで行くことにしたんですね。

理由としては二つありまして

  • ⓵ Goでなんかしらのパッチ投げたことがこれまでなかった
  • ⓶ Forkしてメンテナンスし続けるのは辛いのでしたくなかった

こんな感じですね。

Forkするのは最初は良いんですが、だんだんメンテナンスするのが辛くなってくるのでやりたくなかったんですよねぇ……。 それに、Goのライブラリにパッチ投げたこともなかったので「いい機会だしやってみるか」となり、パッチを書くことにしました。

やったこと

実際に作ったPRとしては以下です。

github.com

Zoomではグループというものを設定することができ、グループ単位でMTGとかの設定をすることができるようになっています。

今までは手動でグループにユーザーを追加していたんですが、ユーザー数が多くなると面倒くさかったりします。 で、今回の機能改修ではその辺を自動的にできるようにしたかったので上記のPRを投げた感じですね。

やってることとしては、group_member_post.goというファイルを追加して、ついでにサンプルコードを追加しました。

実際に追加しているコードとしては以下通りです。

package zoom

import "fmt"

// AddMenbersPath - v2 path for add group members
const AddMenbersPath = "/groups/%s/members"

// AddMemberOptions are details about add group members
type AddMemberOptions struct {
    GroupID string   `json:"-"`
    Members []Member `json:"members"`
}

// Member represents an group member
type Member struct {
    ID    string `json:"id"`
    Email string `json:"email"`
}

// ResopnseAddGroupMembers represents response for added member to group
type ResopnseAddGroupMembers struct {
    // IDs has comma-delimited, like 'xxxxxxxxxx,xxxxxxxxxx'
    IDs     string `json:"ids"`
    AddedAt string `json:"added_at"`
}

// AddMembers calls POST /groups/{groupId}/members
func AddMembers(opts AddMemberOptions) (ResopnseAddGroupMembers, error) {
    return defaultClient.AddMembers(opts)
}

// AddMembers calls POST /groups/{groupId}/members
// https://marketplace.zoom.us/docs/api-reference/zoom-api/groups/groupmemberscreate
func (c *Client) AddMembers(opts AddMemberOptions) (ResopnseAddGroupMembers, error) {
    var ret = ResopnseAddGroupMembers{}
    return ret, c.requestV2(requestV2Opts{
        Method:         Post,
        Path:           fmt.Sprintf(AddMenbersPath, opts.GroupID),
        DataParameters: &opts,
        Ret:            &ret,
    })
}

基本的に他の部分と同じような実装にして、かつZoomのAPIに書かれているパラメータを構造体として追加しています。

あと実際に使う場合のサンプルコードは以下の通りです。

package main

import (
    "log"
    "os"

    "github.com/himalayan-institute/zoom-lib-golang"
)

func main() {
    var (
        apiKey    = os.Getenv("ZOOM_API_KEY")
        apiSecret = os.Getenv("ZOOM_API_SECRET")
        userID    = os.Getenv("USER_ID")
        groupID   = os.Getenv("GROUP_ID")
    )

    zoom.APIKey = apiKey
    zoom.APISecret = apiSecret

    addMemberopts := zoom.AddMemberOptions{
        GroupID: groupID,
        Members: []zoom.Member{
            {
                ID: userID,
            },
        },
    }

    member, err := zoom.AddMembers(addMemberopts)
    if err != nil {
        log.Printf("Got add members: %+v\n", err)
    }
    log.Printf("Resopnse add members: %+v\n", member)
}

サンプルの追加と実装の追加はそんなに難しくはなかったですね(まあ、実際には色々フィードバックをもらったので直してたりしましたが……)

あと、CIの設定を弄る必要があるのに早い段階で気づけなかったのはよくなかったなぁと……。

おわりに

とりあえず、仕事の改修にも間に合って無事マージされたので良かったです。 とはいえ、まだ改修しなきゃいけないとことかあるので必要に応じて今後もパッチを投げていきたいですねー。