ペペロミア & memoir開発ブログ

React Nativeで開発しているペペロミア & memoirの技術系記事を投稿してます

アサイン募集中のissueを集めて共有するモンハンのクエストボードみたいな仕組みを作る

管理するメンバーが増える & 複数のRepositoryに跨ったプロジェクトだったりすると issueのアサインに時間が掛かることがあるので、特定の記事をモンハンのクエストボードみたいに見立てて、そこから自分に合ったissueを引き受けるような仕組みを作ると楽そうだなと思い以下のスクリプトを作成

PR

github.com

github.com

実装

大まかな実装は以下の通り

  • Cloud Functions のPub/Subを作成
    • GitHub AppsからTokenを取得
    • GItHub APIから以下の条件でissueを抽出
      • アサイン募集中のラベルが設定されている
      • 誰もアサインされていない
    • 上記のissueを抽出してテキストを作成
    • 作成テキストをKibela APIを使用して記事を更新
  • 上記のCloud FunctionsをCloud Scheduleで定期実行させる

まず、以下の記事を参考にGitHub Appsの作成

zenn.dev

作成したGitHub Appsから以下を取得 - Installation ID → GitHub Appsのinstall Appの画面のURLから値を確認できる - GitHub App ID - GitHub AppのPrivate keysを作成

Private keysはprivate-key.pemにファイル名を変更してカレントのフォルダに配置して以下のコマンドで環境変数を設定

export GITHUB_APP_PRIVATE_KEY=$(cat private-key.pem)
export GITHUB_APP_ID=*****
export INSTALLATION_ID=*****

以下のコードでGitHub APIのトークンを取得できる

postAssignableIssues/function.go

func PostAssignableIssuesPubSub(ctx context.Context, m *pubsub.Message) error {
    InstallationID, err := strconv.Atoi(os.Getenv("INSTALLATION_ID"))
    if err != nil {
        return err
    }
    githubAppID := os.Getenv("GITHUB_APP_ID")

    appID, err := strconv.ParseInt(githubAppID, 10, 64)
    if err != nil {
        return err
    }
    key := os.Getenv("GITHUB_APP_PRIVATE_KEY")
    tr := http.DefaultTransport
    itr, err := ghinstallation.New(tr, appID, int64(InstallationID), []byte(key))
    if err != nil {
        return err
    }

    token, err := itr.Token(ctx)

トークンを使用してGitHub APIを実行する GitHub APIでは、以下のGraphQLでアサイン募集中のラベルが設定されていて、アサインの無いissueを抽出できる

query Repository($owner: String!, $name: String!) {
  repository(owner: $owner, name: $name) {
    issues(first: 100, states: [OPEN], labels: ["アサイン募集中"], orderBy: {field: CREATED_AT, direction: DESC}, filterBy: {assignee: null}) {
      nodes {
        id
        title
        url
      }
    }
  }
}

このGraphQLを使用してissueを抽出してテキストを作成する 実装コードは以下のファイルを参照

https://github.com/wheatandcat/work-tools/blob/fa47608521ed19c9a97ea5d28a0c58bc832c72bb/postAssignableIssues/issue.go

さらに、ここに以下の設定したラベル毎にカテゴリーに分けて表示する実装を追加

ラベル名 内容
RFP Request For Proposalの略。問題を記載しているのでプロポーザルを記載して全体に共有する
ドキュメンテーション ドキュメントにまとめて共有する
設計前 機能の設計書を作成する
運用改善 運用改善系/効率化の対応

上記のラベルが無い場合は開発issueの項目に表示される

実装コードは以下のファイルを参照

github.com

このコードで生成されるテキストが以下の通り ※表示の元になっているissueは、こちら

### ■ tool-test 
#### ドキュメンテーション

 - [06_アサイン募集中_ドキュメンテーション](https://github.com/wheatandcat/tool-test/issues/6)

#### RFP

 - [05_アサイン募集中_ RFP](https://github.com/wheatandcat/tool-test/issues/5)

#### 開発issue

 - 【v1.0.0】[07_アサイン募集中_マイルストーン設定](https://github.com/wheatandcat/tool-test/issues/7)
 - [02_アサイン募集中](https://github.com/wheatandcat/tool-test/issues/2)
 - [01_アサイン募集中](https://github.com/wheatandcat/tool-test/issues/1)

上記のテキストを使用してKibela APIから記事の更新を行う

Kibela APIについては以下を参照 github.com

Kibela APIはGraphQLで実装されているので、以下のQueryで記事の内容の取得

query Note($id: ID!) {
  note(id: $id) {
    id
    title
    url
    content
  }
}

以下のMutationで記事の更新が行える

mutation UpdateNoteContent($input: UpdateNoteContentInput!) {
  updateNoteContent(input: $input) {
    clientMutationId
    note {
      id
      content
    }
  }
}

上記のGraphQLを使用して記事を更新すると以下のような内容で記事が更新される

f:id:wheatandcat:20211229192644p:plain:w530

ここまでで記事の更新は完了なので、次はCloud Functionを以下のコマンドでデプロイする

$ gcloud functions deploy PostAssignableIssuesPubSub --set-env-vars GITHUB_APP_PRIVATE_KEY=$GITHUB_APP_PRIVATE_KEY,GITHUB_APP_ID=$GITHUB_APP_ID,GITHUB_OWNER=$GITHUB_OWNER,INSTALLATION_ID=$INSTALLATION_ID,NOTE_TOKEN=$NOTE_TOKEN,NOTE_ID=$NOTE_ID,NOTE_HOST=$NOTE_HOST --runtime go116 --trigger-resource post_assignable_issues --trigger-event google.pubsub.topic.publish --region asia-northeast1

以下でデプロイされているのを確認

f:id:wheatandcat:20211229192948p:plain

最後に上記のCloud FunctionをCloud Scheduleのジョブに追加 ターゲットタイプをPub/Subでトピックを上記のCloud Functionに設定して追加

f:id:wheatandcat:20211229193504p:plain

上記の設定で定期的にCloud Functionを実行して記事の更新がされるようになる

以上で実装完了。もし同じような問題をプロジェクトで抱えていたら、こんな方法で自動化できるかもという話でした。