ジョブカン事業部のアドベントカレンダー15日目です。
日常的にEmacsのOrg modeを個人のタスク管理ツールとして活用しているのですが、GitHubのレビューリクエストをタスクとして管理するノウハウを構築できたので記事にしてみたいと思います。
GitHubのUIのみで管理する場合の課題
GitHubで開発しているとPRのレビューの依頼は個人のPull Requestsのページの「Review Requests」タブに一覧表示されます。
この機能はあくまで現在のレビューリクエストを把握するのには有用ですが、タスク管理の観点からみると以下の課題があります。
- レビューリクエストに対してタスクの状態(TODO,WAIT,DONE等)を設定できない
- レビューリクエストに対して予想工数を設定できない
- レビューリクエストに対して実工数の記録ができない
- レビューリクエストに優先度を設定できない
- レビューリクエスト一覧でレビューリクエストされた日付を表示できない
- レビュー完了したPRは、レビューリクエスト一覧から消えてしまう
- 自身がレビューしたPRを再度参照したい場合に困る
以上のようにGitHubのレビューリクエスト一覧をタスク管理機能としてそのまま利用すると不都合が生じます。
そこで、Org modeを用いてGitHubのレビューリクエストを管理する私のやり方を紹介します。
GitHubのレビューリクエストをタスク管理する方針
上記の問題を解決するため、GitHubのレビューリクエストを自身が使用しているタスク管理ツールである、EmacsのOrg modeで扱うためのワークフローを構築しました。
次の手順でレビューリクエストを処理します。
- 未登録のレビューリクエストを一覧表示する
- ブラウザ上でレビューリクエストがきたPRを表示して内容を確認
- 必要な情報を入力してタスクとして登録 (テンプレートを使用した手動登録)
- レビューを実施 (タスク管理システム上で工数計測などをする)
- レビュー完了 (レビューのサブミットの後、タスク側の状態も終了する)
あくまでタスクとしての登録は手動であるものの、タスク管理システムで管理されていない未登録のレビューリクエストの一覧を表示するところまでは自動化するというバランスを取っています。
自動的にタスクを挿入することも検討はしたのですが、私の運用ではレビューリクエストを受信した日付のような、GitHub CLIのAPIでは取得が難しい情報も登録したい点と、自動的にタスクが追記される振る舞いは個人的にはあまり嬉しくなかったためそこまでは対応していません。
前提知識
Emacsについては名前まで知っている方は多いかもしれませんが、Org modeとなると基本的にEmacsを使っている人しか知らない領域になってくると思うのでそれぞれについて基本的な紹介をします。
Emacs とは
GNU EmacsとはFree Software Foundation が公開している拡張可能で自由なテキストエディタであり、かつプログラミング言語Lispの一種であるEmacs Lispの処理系です。
Org mode とは
Org modeとはMarkdownのような構造化されたプレーンテキストフォーマットの一つです。EmacsでOrg mode形式を扱うことで、メモ取り、タスク管理、プロジェクト管理、文書編集、計算ノート、文芸的プログラミングなど、ユーザーが思いつく限りのことを自由に実現する無限の可能性を持ったシステムです。
Org mode でレビュータスクを登録する方法
Org modeのorg-captureという機能を使ってタスクを登録します。
org-captureとは、事前にテンプレートを設定しておいて、Emacs上のどこからでも新しいメモやタスクを素早く追加できるようにするための仕組みです。
自分はレビューリクエストタスクのテンプレートには以下のような設定をしています。
;; org-capture を実行するためのキーバインドの設定
(global-set-key (kbd "C-c c") 'org-capture)
;; テンプレートで使用している org-id-new を読み込む
(require 'org-id)
;; テンプレートの設定(ここではレビューリクエストのタスク起票のみ)
;; レビューリクエスト管理用のファイルは ~/org/review_requests.org にて管理する前提
(setq org-capture-templates
'(("R" "レビュー" entry (file+headline "~/org/review_requests.org" "現在のレビューリクエスト")
"* TODO [PR: %^{PR番号}] %^{TITLE} [/]
:PROPERTIES:
:ID: %(org-id-new)
:CUSTOM_ID: %^{organization|example-org1}/%^{リポジトリ|example-repo1}/%\\1
:REQUESTER: %^{依頼者|momotaro|kintaro|issunboshi|kaguyahime|hanasaka|}
:REQUESTED_DATE: %^{REQUESTED_DATE}u
:END:
- PR: https://github.com/%\\3/%\\4/pull/%\\1
- [ ] PRを読んで内容を理解
- [ ] レビュー指針を確認
- [ ] 仕様レベルの問題がないか確認した
- [ ] 実装レベルの問題がないか確認した
- [ ] (問題がある場合) Change Request を投げた
- [ ] Approve した
"
:prepend t
:empty-lines 1
:jump-to-captured t)
))
この状態でC-c c Rとコマンド入力をするとEmacs上で以下の順番でプロンプトが表示されます。
(C-cはControlキーを押しながらcを押下する操作のこと)
-
PR番号: PRの番号を入力 (例:42) -
タイトル: 自由にタイトルを入力 (例:テストタイトル) -
organization: GitHub Organization の識別子 (例:example-org1) -
リポジトリ: リポジトリ名 (例:example-repo1) -
依頼者: 依頼した人の名前 (例:issunboshi)
organization, リポジトリ, 依頼者 は候補の一覧をorg-captureのテンプレートに含めているため選択するUIとなっています。
たとえば依頼者は項目としてmomotaro|kintaro|issunboshi|kaguyahime|hanasakaと設定しているため、この一覧から選択するUIになります(候補外の名前の入力も可能です)。
「PR番号」と「タイトル」と「organization」と「リポジトリ」の入力は自動化していません。原理的には可能な認識ですが、org-captureでここを自動化しても手間の割にメリットが薄いと考えています。
例の通りに入力すると~/org/review_requests.orgに以下のように起票されます。
* 現在のレビューリクエスト
** TODO [PR: 42] テストタイトル [/]
:PROPERTIES:
:ID: 18DBB8AA-D117-46F5-8140-2BE6EA04B07A
:CUSTOM_ID: example-org1/example-repo1/42
:REQUESTER: issunboshi
:REQUESTED_DATE: [2025-12-15 Mon]
:END:
- PR: https://github.com/example-org1/example-repo1/pull/42
- [ ] PRを読んで内容を理解
- [ ] レビュー指針を確認
- [ ] 仕様レベルの問題がないか確認した
- [ ] 実装レベルの問題がないか確認した
- [ ] (問題がある場合) Change Request を投げた
- [ ] Approve した
カーソルを ** TODO [PR: 42] テストタイトル [/] の中において C-c C-o (or M-x org-open-at-point) を実行するとブラウザが開いてPRが表示されます。
私の環境のEmacsだと次のように表示され、青色のリンク部分はクリック可能です(org-modern パッケージを使用)。
このテキストがOrg mode上で管理されるタスクになります。
CUSTOM_IDにexample-org1/example-repo1/42という文字列が自動的に設定されることが後の処理に影響するため覚えておいてください。
Org modeのAgenda Viewという機能を使うとタスクや日程を表示できるのですが、たとえば~/org/review_requests.orgをAgenda機能の対象に設定した状態でタスク一覧を表示すると
review_requests:TODO [PR: 42] テストタイトル [0/6]
のように表示されるようになり、タスク管理システム上で扱えるようになります。
GitHub のレビューリクエストを一覧表示する
GitHub 上のレビューリクエストを取得するにはGitHub CLIを使用します。
GitHub CLIをインストールし、gh auth login等の認証を済ませた状態で実行すると、自身宛てのレビューリクエストの一覧が表示されます。
gh search prs --state=open --review-requested=@me
Org modeで扱いやすいようにjson出力を整形して出力する場合は次のようにします。
(JSONの整形にはjqコマンドを使用しているため、未導入の場合はインストールが必要です)
gh search prs --state=open --review-requested=@me --json repository,number,title,url \
| jq -r '.[] | [(.repository|.nameWithOwner) + "/" + (.number|tostring), "[[" + .url + "][" + (.title) + "]]" ] | @tsv'
~/org/review_requests.org に以下のコードブロックを追記し、
* GitHub上のレビューリクエスト一覧
#+NAME: fetch-review-requests
#+begin_src shell
gh search prs --state=open --review-requested=@me --json repository,number,title,url | jq -r '.[] | [(.repository|.nameWithOwner) + "/" + (.number|tostring), "[[" + .url + "][" + (.title) + "]]" ] | @tsv'
#+end_src
C-c C-v C-b (or M-x org-babel-execute-buffer)を実行すると、 org-babelの機能によってshellのコードが実行されて表が追記されます。
(デフォルトではorg-babelでコード実行をする前に、本当に実行してよいかの問い合わせが挟まります。これを無効化したい場合はOrg mode のドキュメントのCode Evaluation and Security Issuesを参照して検討してください)
* GitHub上のレビューリクエスト一覧
#+NAME: fetch-review-requests
#+begin_src shell
gh search prs --state=open --review-requested=@me --json repository,number,title,url | jq -r '.[] | [(.repository|.nameWithOwner) + "/" + (.number|tostring), "[[" + .url + "][" + (.title) + "]]" ] | @tsv'
#+end_src
#+RESULTS: fetch-review-requests
| example-org1/example-repo1/42 | [[https://github.com/example-org1/example-repo1/42][テストタイトル]] |
| example-org1/example-repo1/43 | [[https://github.com/example-org1/example-repo1/43][テストタイトル2]] |
私の環境のEmacsで確認すると以下のように表示されます。
- 未登録のレビューリクエストを一覧表示する
未登録のレビューリクエストの一覧を表示できれば、Org modeの管理下にないレビューリクエストを簡単に確認でき、タスクとして認識していないレビューリクエストを把握できるようになります。
このためにはタスクに設定したCUSTOM_IDというプロパティの値を使用して対応します。
org-captureによるタスクの起票時には次の形式でCUSTOM_IDが設定されるようにしています。
<organization>/<repository>/<issue-number>
このスラッシュ区切りの3つ組みはGitHub上でユニークなPRの識別子です。
たとえばですが、先ほどの例のタスクではexample-org1/example-repo1/42がCUSTOM_IDに設定されます。
APIで取得したレビューリクエストの一覧からOrg modeに登録済みのCUSTOM_IDのものを除くことで、未登録のレビューリクエストの一覧を得ます。
これはorg-babel-execute-bufferコマンドがファイルの先頭からコードブロックを順に実行するという性質を活用する方針で実装します。
まず、ファイルの先頭に以下のコードブロックを追記して、登録済みのCUSTOM_IDを管理するための変数を宣言して初期化します。
#+begin_src emacs-lisp
(defvar review-requests--custom-ids)
(setq review-requests--custom-ids '())
#+end_src
また、それぞれのタスクのプロパティを取得するためのテンプレート用のコードも追加します。
#+NAME: update-custom-ids
#+begin_src emacs-lisp :eval never
(let ((id (org-entry-get nil "CUSTOM_ID" t)))
(when (and id (not (member id review-requests--custom-ids)))
(push id review-requests--custom-ids)))
nil
#+end_src
このコードは、:eval neverとしてしているためorg-babel-execute-bufferを実行しても実行されません。このコードはそれぞれのタスクの内部に埋め込んで実行します。
org-captureのテンプレートを編集して以下のように、タスクのテンプレートにコードブロックを追加します。
;; org-capture を実行するためのキーバインドの設定
(global-set-key (kbd "C-c c") 'org-capture)
;; テンプレートで使用している org-id-new を読み込む
(require 'org-id)
;; テンプレートの設定(ここではレビューリクエストのタスク起票のみ)
;; レビューリクエスト管理用のファイルは ~/org/review_requests.org にて管理する前提
(setq org-capture-templates
'(("R" "レビュー" entry (file+headline "~/org/review_requests.org" "現在のレビューリクエスト")
"* TODO [PR: %^{PR番号}] %^{TITLE} [/]
:PROPERTIES:
:ID: %(org-id-new)
:CUSTOM_ID: %^{organization|example-org1}/%^{リポジトリ|example-repo1}/%\\1
:REQUESTER: %^{依頼者|momotaro|kintaro|issunboshi|kaguyahime|hanasaka|}
:REQUESTED_DATE: %^{REQUESTED_DATE}u
:END:
- PR: https://github.com/%\\3/%\\4/pull/%\\1
- [ ] PRを読んで内容を理解
- [ ] レビュー指針を確認
- [ ] 仕様レベルの問題がないか確認した
- [ ] 実装レベルの問題がないか確認した
- [ ] (問題がある場合) Change Request を投げた
- [ ] Approve した
** チェックスクリプト
#+begin_src emacs-lisp :noweb yes
<<update-custom-ids>>
#+end_src
"
:prepend t
:empty-lines 1
:jump-to-captured t)
))
この状態でタスクを起票しなおすとこのようになります。
** TODO [PR: 42] テストタイトル [0/0]
:PROPERTIES:
:ID: 211044D3-4FD7-438D-872B-52F1354BD493
:CUSTOM_ID: example-org1/example-repo1/42
:REQUESTER: issunboshi
:REQUESTED_DATE: [2025-12-15 Mon]
:END:
- PR: https://github.com/example-org1/example-repo1/pull/42
- [ ] PRを読んで内容を理解
- [ ] レビュー指針を確認
- [ ] 仕様レベルの問題がないか確認した
- [ ] 実装レベルの問題がないか確認した
- [ ] (問題がある場合) Change Request を投げた
- [ ] Approve した
*** チェックスクリプト
#+begin_src emacs-lisp :noweb yes
<<update-custom-ids>>
#+end_src
nowebという機能で<<update-custom-ids>>が前述のコードブロックに置換されるので、このコードが実行されたタイミングでreview-requests--custom-idsにCUSTOM_IDが追加されます。
そして、ファイルの最後に以下を追加すれば未登録のレビューリクエストの一覧を取得できます。
*** 未登録のレビューリクエスト一覧を更新
#+NAME: unregistered-requests
#+begin_src emacs-lisp :var tbl=fetch-review-requests
(let ((unregistered-table '()))
(dolist (row tbl)
(unless (member (car row) review-requests--custom-ids)
(push (cdr row) unregistered-table)))
unregistered-table)
#+end_src
この状態で C-c C-v C-b (or M-x org-babel-execute-buffer)を実行すると、
*** 未登録のレビューリクエスト一覧を更新
#+NAME: unregistered-requests
#+begin_src emacs-lisp :var tbl=fetch-review-requests
(let ((unregistered-table '()))
(dolist (row tbl)
(unless (member (car row) review-requests--custom-ids)
(push (cdr row) unregistered-table)))
unregistered-table)
#+end_src
#+RESULTS: unregistered-requests
| [[https://github.com/example-org1/example-repo1/43][テストタイトル2]] |
のように未登録のレビューリクエストの一覧が表示されるようになります。
文書の最後に表示されても使い勝手が悪いため、#+RESULTS: unregistered-requestsは現在のレビューリクエストのところに置くとよいでしょう。
最終的にはこのような形になります。
#+begin_src emacs-lisp
(defvar review-requests--custom-ids)
(setq review-requests--custom-ids '())
#+end_src
#+NAME: update-custom-ids
#+begin_src emacs-lisp :eval never
(let ((id (org-entry-get nil "CUSTOM_ID" t)))
(when (and id (not (member id review-requests--custom-ids)))
(push id review-requests--custom-ids)))
nil
#+end_src
* 現在のレビューリクエスト
未登録の一覧 (C-c C-v C-b で更新)
#+RESULTS: unregistered-requests
| [[https://github.com/example-org1/example-repo1/43][テストタイトル2]] |
** TODO [PR: 42] テストタイトル [0/0]
:PROPERTIES:
:ID: 211044D3-4FD7-438D-872B-52F1354BD493
:CUSTOM_ID: example-org1/example-repo1/42
:REQUESTER: issunboshi
:REQUESTED_DATE: [2025-12-15 Mon]
:END:
- PR: https://github.com/example-org1/example-repo1/pull/42
- [ ] PRを読んで内容を理解
- [ ] レビュー指針を確認
- [ ] 仕様レベルの問題がないか確認した
- [ ] 実装レベルの問題がないか確認した
- [ ] (問題がある場合) Change Request を投げた
- [ ] Approve した
*** チェックスクリプト
#+begin_src emacs-lisp :noweb yes
<<update-custom-ids>>
#+end_src
* GitHub上のレビューリクエスト一覧
#+NAME: fetch-review-requests
#+begin_src shell
gh search prs --state=open --review-requested=@me --json repository,number,title,url | jq -r '.[] | [(.repository|.nameWithOwner) + "/" + (.number|tostring), "[[" + .url + "][" + (.title) + "]]" ] | @tsv'
#+end_src
#+RESULTS: fetch-review-requests
| example-org1/example-repo1/42 | [[https://github.com/example-org1/example-repo1/42][テストタイトル]] |
| example-org1/example-repo1/43 | [[https://github.com/example-org1/example-repo1/43][テストタイトル2]] |
** 未登録のレビューリクエスト一覧を更新
#+NAME: unregistered-requests
#+begin_src emacs-lisp :var tbl=fetch-review-requests
(let ((unregistered-table '()))
(dolist (row tbl)
(unless (member (car row) review-requests--custom-ids)
(push (cdr row) unregistered-table)))
unregistered-table)
#+end_src
これで、GitHubのレビューリクエストをOrg mode上のタスクとして管理し、未登録のレビューリクエスト一覧を簡単なコマンドで更新できる環境を構築できました。
再レビュー依頼を検知する
レビューを終えた後に再度レビュー依頼が来た場合はどうすればいいでしょうか。
再レビュー依頼に気づけないとレビューを放置してしまうため、再レビュー依頼を検知する仕組みは未登録レビューリクエストの検知と同じくらい重要な問題です。
これは、以下のワークフローによって解決しています。
「送信済みのレビューリクエスト」「終了したレビューリクエスト」の二つのセクションを追加し、レビュータスクが完了したタイミングで org-refile によってタスクを「現在のレビューリクエスト」から以下の規則に従って移動します。
- レビューの結果 Change Request の場合
- →「送信済みのレビューリクエスト」にタスクを移動
- レビューの結果 Approve の場合
- → 「終了したレビューリクエスト」にタスクを移動
Change Request の場合は開発者からの返信を期待しているが、Approve した場合は基本的には返信が来ないという理由で二つに分けています。どちらの場合でも開発者が再レビュー依頼をする可能性があるため、「送信済みのレビューリクエスト」と「終了したレビューリクエスト」にあるタスクについて、再度レビュー依頼を出された場合は「未登録の一覧」に表示しています。
こうすることで「未登録の一覧」を見るだけで、常に新しいレビューリクエストを確認できるようにしています。再レビュー依頼を認識した場合は、 org-refile で終了したタスクを再度「現在のレビューリクエスト」に戻す運用としています。
再レビュー依頼検知のロジック
「送信済みのレビューリクエスト」と「終了したレビューリクエスト」にあるPRが再レビュー依頼されたときに、「未登録の一覧」に表示する仕組みについて説明します。
未登録のレビューリクエスト検知は、GitHubのレビューリクエストのPR一覧から、すでに登録済みのPRを引くことによって実現していました。そして、登録済みのPRはそれぞれのタスクに埋め込んだコードブロックで自身のCUSTOM_IDを登録済みリストに追加することで実現していました。
よって、何もしない場合は「送信済みのレビューリクエスト」、「終了したレビューリクエスト」にタスクを移動しても同じようにコード実行が走ってしまうため、引き続き登録済み扱いとなってしまいます。
これは、コード実行を抑制すれば未登録として扱えるということでもあります。そして、Org modeには特定セクションのコード実行を抑制する手段があるため、「送信済みのレビューリクエスト」と「終了したレビューリクエスト」以下のタスクについてはコードが実行されないようにすれば、再レビュー依頼を検知する仕組みを実現できます。以下のように :header-args:emacs-lisp: :eval never をセクションのプロパティにセットしておけば完璧です。
* 送信済みのレビューリクエスト
:PROPERTIES:
:header-args:emacs-lisp: :eval never
:END:
* 終了したレビューリクエスト
:PROPERTIES:
:header-args:emacs-lisp: :eval never
:END:
これで再度レビュー依頼が来ても「未登録の一覧」にPRが表示されるため、見逃しがなくなりました。
仕上げ
詳細な説明は省略しますが、私が実際に使用している最終形を紹介します。以下を追加しています。
- Column View を使用した予想工数と実工数の表示
- 実工数はorg-clock-inで記録
- タスク管理するセクションに(
:now:review:など)を設定して Org Agenda でタスク一覧を表示したときに状況を把握しやすくする
Column Viewを使用した時のEmacs上での表示は以下の通りです。
Org Agenda でタスクを Column View で表示した場合の表示

最終状態の ~/org/review_requests.org を以下に示します。
(長いため折りたたんでいます)
最終版の ~/org/review_requests.org
TITLE: レビューリクエスト
#+OPTIONS: ^:nil
#+PROPERTY: header-args:emacs-lisp :eval never-export
#+PROPERTY: header-args:bash :eval never-export
本文書で受信したレビューリクエストを管理します。
まず、レビューリクエストの管理に必要な変数宣言とその初期化を行います。
#+begin_src emacs-lisp
(defvar review-requests--custom-ids)
(setq review-requests--custom-ids '())
#+end_src
それぞれのタスクに埋め込むコードブロックで、現在のエントリの =CUSTOM_ID= を取得し、変数 =review-requests--custom-ids= に追加します。
#+NAME: update-custom-ids
#+begin_src emacs-lisp :eval never
(let ((id (org-entry-get nil "CUSTOM_ID" t)))
(when (and id (not (member id review-requests--custom-ids)))
(push id review-requests--custom-ids)))
nil
#+end_src
* 現在のレビューリクエスト :now:review:
:PROPERTIES:
:COLUMNS: %50ITEM%TODO%Effort(Effort){:}%CLOCKSUM(Real)%20REQUESTER(Requester)%REQUESTED_DATE(Requested)
:END:
レビュー依頼を受けて、まだレビューが完了していないレビューリクエストを管理します。
保留する場合や、送信済み、終了した場合はタスクの状態を更新して、
=org-refile= コマンドを使用してそれぞれのセクションに移動してください。
=org-column= コマンドでカラム表示を切り替えることで、予想工数と実工数を確認できます。
未登録の一覧 (C-c C-v C-b で更新)
#+RESULTS: unregistered-requests
| [[https://github.com/example-org1/example-repo1/43][テストタイトル2]] |
** TODO [PR: 42] テストタイトル [0/0]
:PROPERTIES:
:ID: 211044D3-4FD7-438D-872B-52F1354BD493
:CUSTOM_ID: example-org1/example-repo1/42
:REQUESTER: issunboshi
:REQUESTED_DATE: [2025-12-15 Mon]
:Effort: 0:15
:END:
:LOGBOOK:
CLOCK: [2025-12-15 Mon 13:00]--[2025-12-15 Mon 13:15] => 0:15
:END:
- PR: https://github.com/example-org1/example-repo1/pull/42
- [ ] PRを読んで内容を理解
- [ ] レビュー指針を確認
- [ ] 仕様レベルの問題がないか確認した
- [ ] 実装レベルの問題がないか確認した
- [ ] (問題がある場合) Change Request を投げた
- [ ] Approve した
*** チェックスクリプト
#+begin_src emacs-lisp :noweb yes
<<update-custom-ids>>
#+end_src
** TODO [PR: 37] テストタイトル6 [2/6]
:PROPERTIES:
:ID: CCFBDD6C-34E0-4FD1-AA51-D0FE43FD538C
:CUSTOM_ID: example-org1/example-repo1/37
:REQUESTER: kaguyahime
:REQUESTED_DATE: [2025-12-06 Sat]
:Effort: 3:00
:END:
:LOGBOOK:
CLOCK: [2025-12-07 Sun 13:00]--[2025-12-07 Sun 14:15] => 1:15
:END:
- PR: https://github.com/example-org1/example-repo1/pull/37
- [X] PRを読んで内容を理解
- [X] レビュー指針を確認
- [ ] 仕様レベルの問題がないか確認した
- [ ] 実装レベルの問題がないか確認した
- [ ] (問題がある場合) Change Request を投げた
- [ ] Approve した
*** チェックスクリプト
#+begin_src emacs-lisp :noweb yes
<<update-custom-ids>>
#+end_src
* 保留中のレビューリクエスト :hold:review:
なんらかの理由でレビューを保留しているレビューリクエストを記載します。
** WAIT [PR: 41] テストタイトル3 [1/6]
:PROPERTIES:
:ID: 929057DF-0370-43A5-8139-C9CBEBC330DC
:CUSTOM_ID: example-org1/example-repo1/41
:REQUESTER: kaguyahime
:REQUESTED_DATE: [2025-11-11 Tue]
:END:
- State "WAIT" from "TODO" [2025-11-13 Thu 10:31] \\
レビューリクエストを出したものの現在は修正中らしい
- PR: https://github.com/example-org1/example-repo1/pull/41
- [X] PRを読んで内容を理解
- [ ] レビュー指針を確認
- [ ] 仕様レベルの問題がないか確認した
- [ ] 実装レベルの問題がないか確認した
- [ ] (問題がある場合) Change Request を投げた
- [ ] Approve した
*** チェックスクリプト
#+begin_src emacs-lisp :noweb yes
<<update-custom-ids>>
#+end_src
* 送信済みのレビューリクエスト :sent:review:
:PROPERTIES:
:header-args:emacs-lisp: :eval never
:END:
主に Change Request を送信後、修正待ちのレビューリクエストを管理します。
再度レビューリクエストされた場合は「未登録の一覧」に表示されるため、その場合は =org-refile= で「現在のレビューリクエスト」セクションに移動してください。
※ =:eval never= を設定しているため、ここのタスクの =CUSTOM_ID= は集計されずシステム上は未登録として扱われます
** SENT [PR: 40] テストタイトル4 [5/6]
CLOSED: [2025-11-13 Thu 10:35]
:PROPERTIES:
:ID: DAE049FF-D177-4B9B-859F-A7DE52C6EC14
:CUSTOM_ID: example-org1/example-repo1/40
:REQUESTER: momotaro
:REQUESTED_DATE: [2025-11-12 Wed]
:END:
- PR: https://github.com/example-org1/example-repo1/pull/40
- [X] PRを読んで内容を理解
- [X] レビュー指針を確認
- [X] 仕様レベルの問題がないか確認した
- [X] 実装レベルの問題がないか確認した
- [X] (問題がある場合) Change Request を投げた
- [ ] Approve した
*** チェックスクリプト
#+begin_src emacs-lisp :noweb yes
<<update-custom-ids>>
#+end_src
* 終了したレビューリクエスト :closed:review:
:PROPERTIES:
:header-args:emacs-lisp: :eval never
:END:
レビュー完了、もしくはキャンセルされたレビューリクエストを管理します。
再度レビューリクエストされた場合は「未登録の一覧」に表示されるため、その場合は =org-refile= で「現在のレビューリクエスト」セクションに移動してください。
※ =:eval never= を設定しているため、ここのタスクの =CUSTOM_ID= は集計されずシステム上は未登録として扱われます
** DONE [PR: 39] テストタイトル5 [6/6]
CLOSED: [2025-11-13 Thu 10:35]
:PROPERTIES:
:ID: 35B3CACB-9EC5-4AEB-B954-A1A62374C9AC
:CUSTOM_ID: example-org1/example-repo1/39
:REQUESTER: kintaro
:REQUESTED_DATE: [2025-11-12 Wed]
:END:
- PR: https://github.com/example-org1/example-repo1/pull/39
- [X] PRを読んで内容を理解
- [X] レビュー指針を確認
- [X] 仕様レベルの問題がないか確認した
- [X] 実装レベルの問題がないか確認した
- [X] (問題がある場合) Change Request を投げた
- [X] Approve した
*** チェックスクリプト
#+begin_src emacs-lisp :noweb yes
<<update-custom-ids>>
#+end_src
** CANCELED [PR: 38] テストタイトル5 [0/6]
CLOSED: [2025-11-13 Thu 10:38]
:PROPERTIES:
:ID: 6B56285B-F39A-4864-B9B5-9931779BB678
:CUSTOM_ID: example-org1/example-repo1/38
:REQUESTER: kintaro
:REQUESTED_DATE: [2025-11-12 Wed]
:END:
- PR: https://github.com/example-org1/example-repo1/pull/38
- [ ] PRを読んで内容を理解
- [ ] レビュー指針を確認
- [ ] 仕様レベルの問題がないか確認した
- [ ] 実装レベルの問題がないか確認した
- [ ] (問題がある場合) Change Request を投げた
- [ ] Approve した
*** チェックスクリプト
#+begin_src emacs-lisp :noweb yes
<<update-custom-ids>>
#+end_src
* GitHub上のレビューリクエスト一覧
#+NAME: fetch-review-requests
#+begin_src shell
gh search prs --state=open --review-requested=@me --json repository,number,title,url | jq -r '.[] | [(.repository|.nameWithOwner) + "/" + (.number|tostring), "[[" + .url + "][" + (.title) + "]]" ] | @tsv'
#+end_src
#+RESULTS: fetch-review-requests
| example-org1/example-repo1/42 | [[https://github.com/example-org1/example-repo1/42][テストタイトル]] |
| example-org1/example-repo1/43 | [[https://github.com/example-org1/example-repo1/43][テストタイトル2]] |
** 未登録のレビューリクエスト一覧を更新
#+NAME: unregistered-requests
#+begin_src emacs-lisp :var tbl=fetch-review-requests
(let ((unregistered-table '()))
(dolist (row tbl)
(unless (member (car row) review-requests--custom-ids)
(push (cdr row) unregistered-table)))
unregistered-table)
#+end_src
まとめ
Org modeでレビューリクエストを管理することで大変快適なレビューライフを過ごせています。Emacsはプログラミング用のエディタとしてよく知られていますが、タスク管理システムとしても有用ですので是非活用してみてください。
おわりに
DONUTSでは新卒中途問わず積極的に採用活動を行っています。
詳細はこちらをご確認ください。



