Node.jsでGitHubのオーガナイゼーションとチームにユーザーを追加する


GitHubのチームはオーガナイゼーションに紐づくサブ組織的な位置付けです。

## GitHubのオーガナイゼーションとチーム

このような階層構造になっています。

```
オーガナイゼーション1
	|--チームA
	|--チームB 
	|--チームC
```

オーガナイゼーションのメンバーとして管理権限がないと、オーガナイゼーション外のユーザーをオーガナイゼーション配下のチームに追加することは出来ません。

例えば、チームBにだけメンバーを追加しようとしても、オーガナイゼーション1に先に追加しないといけません。さらにこれをやる場合、オーガナイゼーション1の管理権限がないといけません。

オーガナイゼーション1に所属している管理権限がない人でもチームに人を追加できるように出来ないかと思い、APIを使ってみました。

## GitHubのAPIアクセストークンを発行

こちら（[個人アクセストークンを使用する](https://docs.github.com/ja/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token))をみてアクセストークンを取得します。


`Settings` > `Developer settings` > `Personal access tokens`で見れます

オーガナイゼーションだけのコントロールをしたいのでこんなチェックにしてトークンを発行しました。

> ![スクリーンショット 2021-06-09 1.25.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/0fcc7324-3661-a602-7e2c-132f785a3ae5.png "スクリーンショット 2021-06-09 1.25.02.png")

`ghp_`で始まる文字列がトークンとして発行されます。

> ![スクリーンショット 2021-06-09 1.26.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/e7c6cbc4-5814-3ba0-15cc-3ccba7c8d51d.png "スクリーンショット 2021-06-09 1.26.12.png")

## GitHubのチーム追加のAPIをまずはCURLで試す

[Add or update team membership for a user](https://docs.github.com/en/rest/reference/teams#add-or-update-team-membership-for-a-user)を見てみます。

```
/orgs/{org}/teams/{team_slug}/memberships/{username}
```

という形式でAPIを叩くことで利用できます。

```bash
$ curl -u {ORG_NAME}:{トークン} -X PUT -H "Accept: application/vnd.github.inertia-preview+json" https://api.github.com/orgs/{ORG_NAME}/teams/{TEAM_NAME}/memberships/{USER_NAME} -d '{"role":"member"}'
```

こんな形式で利用することができました。

## Node.js（axios）からAPIを利用する

先程のCURLのコマンドからaxiosに書き換えてみます。-uオプションはベーシック認証なんですね。

> [逆引きcurlコマンドのオプション一覧](https://www.setouchino.cloud/blogs/99)

```bash
$ npm i axios
```

```app.js
const axios = require(`axios`);

const gh = async () => {
    const TOKEN = `トークンを指定`;

    const ORG = `protoout`; //追加先のオーガナイゼーション
    const TEAM = `protoout-student`; //追加するチーム名
    const USER_NAME = `n0bisuke`; //追加するユーザー

    const BASE_URL = `https://api.github.com`;
    const PATH = `/orgs/${ORG}/teams/${TEAM}/memberships/${USER_NAME}`
    
    const config = {
        baseURL: BASE_URL,
        url: PATH,
        method: 'put',
        headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/vnd.github.inertia-preview+json',
        },
        auth: {
            username: ORG,
            password: TOKEN
        },
        data: {
            'role': 'member' //固定 API経由で管理者を追加することはあんまりなさそう
        }
    };
        
    const res = await axios.request(config);
    console.log(res.data);

}

gh();
```

実行結果

```bash
$ node app.js
{
  state: 'active',
  role: 'maintainer',
  url: 'https://api.github.com/organizations/XXXXXX/team/XXXXXX/memberships/n0bisuke'
}
```

すでに入っているもしくは招待に成功すると、`acitve`のステータスが返ってきます。

オーガナイゼーション外部の人を招待する場合は、一旦メールがユーザーに飛び、ユーザーが許可するとチームにも追加されるという流れなので、最初は`pending`のステータスになると思います。



## まとめ

こんな感じでオーガナイゼーション招待&チーム追加ができました。

ユーザーにはメールが飛んでいるので、オーガナイゼーションに参加してもらいます。ユーザーが参加ボタンを押すことでオーガナイゼーションにやっと追加されるので、追加後にはユーザーに確認を入れると良さそうですね。

実際の運用だと、こんな感じでDiscordのBOTから呼び出せるようにしてみています。
> ![スクリーンショット 2021-06-09 20.03.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/3c3fbf38-6424-733f-1c58-535fd3b69280.png "スクリーンショット 2021-06-09 20.03.20.png")

便利だ。。