GitHubに、Issue formsというリッチなissue入力フォームを作成する機能が今年(2021年)6月に加わったので、その紹介をします。この機能を用いると、小項目に分かれた(構造化された)フォームを提供でき、そこではテキストエリア以外にチェックボックスの利用や必須項目の指定なども可能です。つまり、Google Formsで作れるような入力フォームを提供できます。
なお、この記事の執筆時点(2021年10月)では、この機能は公開リポジトリのみで利用可能なベータ版という位置づけです。広く使われてフィードバックが十分に集まり、Organization内のプライベートリポジトリでも利用可能な状態になってくれるとありがたいと思ったので、この記事を書いています。
用語
- 入力者:フォームを用いてissueを報告する人(フォームのユーザ)を指します。
- フォーム画面:issueのフォームが表示される入力画面のことを、ここではこのように呼ぶことにします。
GitHub Issuesのデフォルトの入力フォーム
みなさんご存知のとおりですが、GitHub Issuesは、デフォルトでは単一の広いテキストエリアでしかないフォームを提供しています。
Markdownで自由に入力できるので、様々なフィードバックを気兼ねなく入力してもらうにはとても便利です。他方で、集めたい情報が明確な場合は必ずしも使いやすいわけではありません。たとえば、こういったケースがあります。
- 入力してほしいと思った情報が必ずしも含まれていない。当然ながら、足りない情報を伝えて再度入力してもらう、といったやりとりが必要になってしまう。
- 入力してほしいと思った情報が含まれていたとしても、ある入力者は冒頭に書き、ある入力者は最後に書き、ある入力者は長い文章の中に含め、とバラバラ。中の人が情報をパッと把握するという観点からは扱いにくい。
Issueテンプレート
この利便性の問題を緩和するために、長らく、GitHub Issueテンプレートという機能が使われていました。これは、テンプレートをMarkdownで用意することで、そのテンプレートに従って入力してもらうというものです。入力内容に含めてほしい情報や明確にしてほしいポイントを入力者に伝えることが可能なので、協力的な入力者であれば、初見であっても一発で適切な情報を集めることが可能です。
GitHub Issueテンプレートを使うには、 .github/ISSUE_TEMPLATE/
というディレクトリをリポジトリルート直下に作成し、その中にMarkdownファイルを配置します。バグ報告や新機能提案など、issue報告が必要になるケースはたいてい複数存在し、含めてほしい情報はそれぞれのケースで異なりますので、複数のMarkdownファイルを配置できます。
テンプレートの設定例
階層構造:
.
├── .github
│ └── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── enhancement_request.md
:
設定内容(の最初の10行ずつ):
% head .github/ISSUE_TEMPLATE/bug_report.md
---
name: Bug report
about: Create a report to help us improve
labels: bug
---
<!-- Thanks for filing a 🐛 bug report 😄! -->
**Problem**
<!-- A clear and concise description of what the bug is. -->
% head .github/ISSUE_TEMPLATE/enhancement_request.md
---
name: Enhancement request
about: Suggest an enhancement for this project
labels: enhancement
---
<!-- Thanks for filing an 🙋 enhancement request 😄! -->
**Describe the problem you are trying to solve**
<!-- A clear and concise description of the problem this enhancement request is trying to solve. -->
上記テンプレートの実際の見え方
入力者が「New issue」のボタンを押すと、報告したいissueのカテゴリを選ぶ画面が表示されます。ここには、各テンプレートのヘッダのname
およびabout
の情報が使われます。
選ぶと、フォーム画面はこのようになっています。
入力内容としてテンプレートの内容が予め設定されていることがわかります。また、テンプレートヘッダのlabels
で設定したラベル(bug
)が自動的に設定されています。
Issueテンプレートの少し不便な点
Issueテンプレートは長らく使われており、全般的にはとてもよく機能していたと思います。
しかし、これはあくまでテンプレートなので、少し不便な点もあったように思います。
- Markdownによるテンプレートの表現方法が、テンプレート作成者によって異なる
- 説明をHTMLのコメント(
<!-- ... -->
)で表現する人もいれば、平文にする人もいる
- 説明をHTMLのコメント(
- 報告時に、自分の入力で上書きしてしまったほうがよいのか、テンプレートのテキストを残した上で追記したほうがよいのか、入力者が迷うケースがある
- テンプレートのテキストが例示と思われる部分は、たいていの人は上書きする
- テンプレートのテキストが説明と思われる部分は、残す人も削除する人もいるし、残すか迷うケースもある
- いざとなれば入力者がテンプレートを完全に無視して自由に入力できる(入力欄に最初に入っているテキストを消去して一から書けばよい)
- (細かいですが)項目の表現方法がテンプレート作成者によってまちまちで、人間の認識力に依存している
-
#
や##
で表現するケース -
####
など、より下位の見出しを用いるケース(#
や##
だとフォントが大きくなりすぎるので?) - 太字として表示するケース
-
Issue forms
Issue formsは、(おそらく)こういった不便な点を解消し、よりよいユーザ体験を提供するために作られました。具体的には、issueを入力項目に細分化し、各項目に見出しや説明を加えることが可能です。各入力項目には、テキスト入力以外に選択式(チェックボックスやドロップダウン)も使えます。また、入力を伴わない、単なる説明の表示のためのブロックを加えることもでき、そこにはMarkdownでリンクや箇条書きなども含めることが可能です。
実例
具体的に見たほうが早いと思うので、例を載せます。
例1:github/docsリポジトリのimprove-existing-docs
github/docsリポジトリのimprove-existing-docsではこのようなフォームが実現されています。自分のブラウザで見たい方はこちらからアクセスできます。
スクリーンショット:
これを実現するためのYAML:
name: Improve existing content
description: Make a suggestion to improve the content in an existing article.
labels:
- content
body:
- type: markdown
attributes:
value: |
**HUBBERS!!** This is the github/docs open source repo. You may want to open an issue in the internal-only github/docs-content repo instead.
* For questions, ask in [Discussions](https://github.com/github/docs/discussions).
* Before you file an issue read the [Contributing guide](https://github.com/github/docs/blob/main/CONTRIBUTING.md).
* Check to make sure someone hasn't already opened a similar [issue](https://github.com/github/docs/issues).
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: This project has a Code of Conduct that all participants are expected to understand and follow.
options:
- label: I have read and agree to the GitHub Docs project's [Code of Conduct](https://github.com/github/docs/blob/main/CODE_OF_CONDUCT.md)
required: true
- type: textarea
attributes:
label: What article on docs.github.com is affected?
description: Please link to the article you'd like to see updated.
validations:
required: true
- type: textarea
attributes:
label: What part(s) of the article would you like to see updated?
description: |
- Give as much detail as you can to help us understand the change you want to see.
- Why should the docs be changed? What use cases does it support?
- What is the expected outcome?
validations:
required: true
- type: textarea
attributes:
label: Additional information
description: Add any other context or screenshots about the feature request here.
validations:
required: false
また、このフォームを用いて送信、登録された内容(登録内容)は、たとえばこんな感じになります。
登録内容の例:
例2:pandas-dev/pandasリポジトリのinstallation_issue
pandas-dev/pandasリポジトリのinstallation_issueではこのようなフォームが実現されています。自分のブラウザで見たい方はこちらからアクセスできます。
スクリーンショット:
これを実現するためのYAML:
name: Installation Issue
description: Report issues installing the pandas library on your system
title: "BUILD: "
labels: [Build, Needs Triage]
body:
- type: checkboxes
id: checks
attributes:
options:
- label: >
I have read the [installation guide](https://pandas.pydata.org/pandas-docs/stable/getting_started/install.html#installing-pandas).
required: true
- type: input
id: platform
attributes:
label: Platform
description: >
Please provide the output of ``import platform; print(platform.platform())``
validations:
required: true
- type: dropdown
id: method
attributes:
label: Installation Method
description: >
Please provide how you tried to install pandas from a clean environment.
options:
- pip install
- conda install
- apt-get install
- Built from source
- Other
validations:
required: true
- type: input
id: pandas
attributes:
label: pandas Version
description: >
Please provide the version of pandas you are trying to install.
validations:
required: true
- type: input
id: python
attributes:
label: Python Version
description: >
Please provide the installed version of Python.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Installation Logs
description: >
If possible, please copy and paste the installation logs when attempting to install pandas.
value: >
<details>
Replace this line with the installation logs.
</details>
Issue formsの設定(YAML)の文法
設定と実際の表示を見比べれば、どの設定がどの表示に対応しているかは簡単にわかると思いますが、一応、簡単に説明します。基本的には例1を題材として扱いますが、所々例2も使います。
トップレベルの要素
例1で、(body
以外の)トップレベルの要素は次のようになっていました。
name: Improve existing content
description: Make a suggestion to improve the content in an existing article.
labels:
- content
これらのトップレベル要素は、フォーム全体の属性を扱います。
name
はこのフォーム全体の名前です。元々のMarkdownテンプレートの name
と同様、入力者が「New issue」のボタンを押した際に、カテゴリ選択の画面でカテゴリ名として使われます。
description
はこのフォーム全体の説明です。元々のMarkdownテンプレートの about
に相当します。入力者が「New issue」のボタンを押した際に、カテゴリ選択の画面でカテゴリの説明として使われます。
labels
はこのフォームを用いて送信したissueに自動的に設定するラベルの一覧です。元々のMarkdownテンプレートの labels
と同じですが、YAMLのリスト表現になっています。
これら以外に、 assignees
というキーを用いて、issueを誰にアサインするかを設定できます。
また、例2では、次のように title
というキーも含まれていました。
title: "BUILD: "
これは、フォーム画面を開いた際にissueのタイトル入力欄に自動的に設定される初期値です。issueテンプレートでもヘッダのtitle
フィールドで指定可能でした。プレースホルダー(例示のために薄色で表示され、ユーザが実際に入力すると消えるテキスト)ではなく、初期値となっているので、たとえばこの場合、入力者は「BUILD: 」というテキストに続けて実際のタイトルを入力することが期待されています。
フォーム要素
トップレベルのbody
に設定された内容がフォームの本体(ボディ)となり、実際のフォーム画面の表示に使われます。ボディの値は、個々のパーツ(フォーム要素)のリストとして設定する必要があります。フォーム要素とは、前述の「入力項目」とほぼ同じです(この後説明するように、入力を伴わない項目も表現できます)。
個々のフォーム要素には、 type
と attributes
の2つのキーを必ず設定する必要があります。type
は要素の種類(タイプ)を指定するもの、 attributes
は属性です。
ほかに id
と validations
も任意で設定できます。id
はフォーム内での識別子なので、フォーム内でユニークでなくてはいけません(同じ値を複数使えないということです)。id
の役割については後述します。
フォーム要素にはいくつかのタイプがあるので、先程の例を用いて、フォーム要素のタイプを1つずつ見ていきましょう。
markdownタイプ
- type: markdown
attributes:
value: |
**HUBBERS!!** This is the github/docs open source repo. You may want to open an issue in the internal-only github/docs-content repo instead.
* For questions, ask in [Discussions](https://github.com/github/docs/discussions).
* Before you file an issue read the [Contributing guide](https://github.com/github/docs/blob/main/CONTRIBUTING.md).
* Check to make sure someone hasn't already opened a similar [issue](https://github.com/github/docs/issues).
markdown
タイプのフォーム要素は、ユーザの入力を伴わないブロックです。この例にあるように、リンクや箇条書きもMarkdownで記載できるので、入力前に入力者に読んでおいてほしい内容、入力者へのメッセージなどがあれば、これを使うのがよいでしょう。
attributes
のvalue
の値がそのまま表示に使われます。YAMLの記法で、複数行のMarkdownをYAML内に埋め込んでいます。
checkboxesタイプ
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: This project has a Code of Conduct that all participants are expected to understand and follow.
options:
- label: I have read and agree to the GitHub Docs project's [Code of Conduct](https://github.com/github/docs/blob/main/CODE_OF_CONDUCT.md)
required: true
checkboxes
タイプのフォーム要素は、その名前のとおりチェックボックスを入力欄とする入力項目です。チェックボックスなので、フォーム作成者は選択肢を複数入れることができ、入力者も複数のボックスにチェックを入れることが可能です。
選択肢はattributes
のoptions
にリストで設定します。options
の各選択項目にはlabel
でその選択肢を表すテキストを設定する必要があります。
各選択項目は、required
という任意のキーを用いて、チェックを入れることを必須にできます。required
が設定された場合、チェックを入れなければフォームを送信できません。これは、入力者に、さまざまな入力前の同意や確認をしてもらうのによく使われます。なお、Google Formsなどと同様に、必須項目の右肩には *
マークもつきます。
attributes
のlabel
やdescription
は、それぞれフォーム要素の見出しと説明に使われます。これらはmarkdown
タイプ以外のフォーム要素に共通です(必須か任意かは、フォーム要素のタイプによって少し違います)。なお、上の登録内容の例を見て気づいたかもしれませんが、description
は送信、登録された内容には含まれません。
textareaタイプ
- type: textarea
attributes:
label: What article on docs.github.com is affected?
description: Please link to the article you'd like to see updated.
validations:
required: true
textarea
タイプのフォーム要素は、その名前のとおりテキストエリアを入力欄とする入力項目です。attributes
のlabel
やdescription
は、checkboxes
のところで説明したとおり、それぞれフォーム要素の見出しと説明として表示されます。ちなみに、見出しは、入力者がissueを送信して登録される際にはMarkdownの見出しレベル3(###
)になるようです。
上の例のフォーム要素にはvalidations
というキーが含まれており、required: true
となっています。これは、入力を必須とするためのものです。つまり、この「What article on docs.github.com is affected?」というフォーム要素のテキストエリアが空のままでは、フォームを送信できません。必須項目の右肩に *
マークがつくのはチェックボックスの場合と同じです。
例1と例2で使われていないキーを2つ紹介しましょう。次の設定は、pandas-dev/pandasのbug_report.yamlからとってきた例です。
- type: textarea
id: example
attributes:
label: Reproducible Example
description: >
Please follow [this guide](https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports) on how to
provide a minimal, copy-pastable example.
placeholder: >
import pandas as pd
df = pd.DataFrame(range(5))
...
render: python
ここではplaceholder
というキーがattributes
に含まれています。これは、フォーム画面を開いた際にテキストエリアに設定されるプレースホルダーです。プレースホルダーなので、ユーザが実際に入力を始めれば消えます。基本的には、説明だと伝わりにくい入力内容の例示に使うことが多いでしょう。
また、render
というキーもattributes
に含まれています。これは、この入力内容をどのように表示してほしいかを設定するものです。ここでは python
と指定しているので、入力内容にはPythonの文法に従って色がつけられます。そのため、たとえばフォームを送信するとこのような表示になります。
なお、どのような言語が指定できるかは、Linguistの設定を見るとわかります。この言語指定は、GitHub全体で、Markdown内の各コードブロックを表示する際に、特定の言語の文法に従って色をつけるのにも使われるものなので、慣れている人も多いでしょう。
inputタイプ
input
タイプのフォーム要素は例1では使われていないので、例2のフォーム要素を題材として使います。
- type: input
id: platform
attributes:
label: Platform
description: >
Please provide the output of ``import platform; print(platform.platform())``
validations:
required: true
input
タイプのフォーム要素は、1行のテキスト入力欄を扱うフォーム要素です。長い文章の不要な、1行だけで済む内容にはtextarea
ではなくinput
を使うのがよいでしょう。扱いはtextarea
とほぼ同じですが、唯一、render
が指定できません。
dropdownタイプ
dropdown
タイプのフォーム要素も例1では使われていないので、例2のフォーム要素を題材として使います。
- type: dropdown
id: method
attributes:
label: Installation Method
description: >
Please provide how you tried to install pandas from a clean environment.
options:
- pip install
- conda install
- apt-get install
- Built from source
- Other
validations:
required: true
dropdown
タイプのフォーム要素は、ドロップダウンメニューを入力欄とするフォーム要素です。
選択式という点で、ドロップダウンメニューはチェックボックスに似ていますが、設定方法はやや異なります。checkboxes
の場合、options
に指定する各選択項目では、テキストはlabel
という子要素の値として設定しており、このほかに必須項目を指定するrequired
というキーが使えました。dropdown
の場合は、options
に指定する各選択項目はテキストそのものです。
id
ここまで読んできて、フォーム要素のid
の役割がわからないというかたもいるでしょう。id
は何の表示にも関わっていません。識別子だと説明しましたが、フォーム要素の識別が必要な場面は出てきませんでしたし、任意なので、指定しなくても動作上は問題ありません。
実はこれは、フォーム画面を開いた際にフォーム要素に特定の値を自動的に設定するのに使われます。たとえば、例2で用いたpandas-dev/pandasのinstallation_issueにおいて、Python Versionの入力欄を提供するフォーム要素にはid
としてpython
が指定されているので、これを使ってみましょう。
pandas-dev/pandasのinstallation_issueの場合、Web UIで「New issue」を選び、報告のカテゴリとして「Installation Issue」を選ぶとフォーム画面が開きますが、そのフォーム画面のURLは次のようになっているはずです。
https://github.com/pandas-dev/pandas/issues/new?assignees=&labels=Build%2CNeeds+Triage&template=installation_issue.yaml&title=BUILD%3A+
ここで、python
パラメータの値を3.10
に設定する&python=3.10
という文字列をURLのクエリ文字列に加えると、URLは次のようになります。
https://github.com/pandas-dev/pandas/issues/new?assignees=&labels=Build%2CNeeds+Triage&template=installation_issue.yaml&title=BUILD%3A+&python=3.10
このURLから開いたフォーム画面では、Python Version
の入力欄に最初から3.10
というテキストが入ります。
このように、id
を設定しておくと、URLを通じてフォームに値を最初から設定できるようになります。GitHub IssuesのWeb UIを通じて操作するだけならこのようなid
の設定をしても特にメリットはありませんが、プログラムでURLを生成してフォーム画面を開くなど、使い方によっては操作の簡略化が可能になります。使う可能性が少しでもあるなら設定しておくほうがよいでしょう。
なお、説明に用いたpandas-dev/pandasのinstallation_issueのURLですが、わかりやすくするためにクエリ文字列をYAMLで表現すると、次のようになります。
assignees: ""
labels: "Build,Needs Triage"
template: installation_issue.yaml
title: "BUILD: "
installation_issue.yamlに設定されたlabels
、title
、さらには設定が省略された(空の)assignees
が埋め込まれており、labels
とassignees
はフォームの属性を設定するのに使われ、title
は、フォーム画面を開いた際にタイトルにテキストを自動設定するのに使われていることがわかります。
したがって、クエリ文字列を変更すればこれらの動作も変更できます。
Issue formsの実務的な話題
Issue formsの文法や機能はすべて説明したので、実務的な話題をいくつか取り上げます。
設定の編集環境
Issue formsのYAMLの設定ファイルは、文法も簡単ですし、設定ファイルのサイズも小さいので、編集には自分の好きな環境を使えばよいでしょう。GitHubのWeb UIで作業する人が多いと思いますが、私はローカルのVisual Studio Codeで編集しました。
Visual Studio Codeの場合、.github/ISSUE_TEMPLATEディレクトリ内のYAMLファイルはIssue formsの文法に従う必要があることを理解してくれており、自動的に補完が効きます。
たとえば name
などのキーは補完してくれます。また、 body
に新たなフォーム要素を加えると自動的に type:
まで入れてくれる、 a
で attributes
を補完入力すると自動的に value:
まで入れてくれる、など、それなりに便利です(うまく認識せずやり直したこともたまにありましたが、まぁ大きな問題ではありません)。
今のところプレビューや文法のvalidationはローカルではできないので、YAMLファイルを編集したらGitで適当なブランチにコミットし、GitHub上のリポジトリにpushします。GitHubのWeb UIでそのブランチに移動してYAMLファイルを開くと、YAMLで書かれたソースではなく入力画面のプレビューを表示してくれるはずです(トップレベルのbody
以外は上部にテーブルで表示されます)。文法上の問題があれば表示してくれるようです。
GitHubのWeb UIでIssue formsのYAMLファイルを表示した様子:
Web UIで作業していてもプレビューは問題になっているようなので、今後改善が入るかもしれません。
IssueテンプレートのMarkdownから移行すべきか?
入力してもらいたい項目(入力内容の構造)が完全に定形になっているなら、IssueテンプレートのMarkdownから移行するほうがよいでしょう。他方で、少し自由度を残したければ、無理に移行しなくてもいいとは思います。
また、現時点でIssue formsでは条件分岐ができません。Issueテンプレートによっては、「先程の質問でこのように回答した人は、このセクションは削除してください」のように条件分岐していることがありますが、現時点でそれはIssue formsで表現できないということです。なので、そういった使い方をしている場合は無理に移行する必要はないかと思います。
とはいえ、Issue formsはまだベータ版なので、条件分岐のサポートが今後入る可能性もあります。実際に、フィードバックとして要望は出ていますので、今後に期待しましょう。
なお、.github/ISSUE_TEMPLATE以下に複数のIssueテンプレートが存在する場合、すべてをIssueテンプレートとIssue formsのどちらかに統一する必要はありません。一部はIssueテンプレートで実装し、一部はIssue formsで実装しても問題ありません。ただし、ファイル名の拡張子を除いた部分で識別されるので、たとえば、.github/ISSUE_TEMPLATE/foobar.mdというIssueテンプレートがある場合、.github/ISSUE_TEMPLATE/foobar.yamlというIssue formsは置けません。
IssueテンプレートのMarkdownからの移行
上で説明したとおりなので、Markdownからの移行は簡単です。たいていは、こんな感じでほぼ機械的に移行できるはずです。
- ヘッダの
name
やtitle
→ そのままトップレベルのname
やtitle
に - ヘッダの
about
→ トップレベルのdescription
に - ヘッダの
labels
やassignees
→ YAMLのリストに変更してトップレベルのlabels
やassignees
に - ボディ → フォーム要素に分解して
body
に配列として入れる(たいていは配列内のフォーム要素はtextarea
タイプが多くなるはず) - 各フォームの見出し → 各フォーム要素の
label
に - 各フォームの説明 → 各フォーム要素の
description
に - 各フォームの例示 → 各テキストエリアの
placeholder
に
今後の期待
Issue formsに関して、私の今後の期待を書いておきます。
抜け道の防止
現在、Issue formsを作成しても、様々な抜け道があります。これらの抜け道を防がないと、場合によっては効果が薄いかもしれません。
たとえば、Web UIに限っても、Issuesの画面の「New issue」を使う以外に、さまざまな方法があります。また、現時点でiOSのGitHubアプリではIssueテンプレートもIssue formsも未対応で、すべてベタ書きのIssueにフォールバックされてしまいます。加えて、一旦登録された後はMarkdownとなるので、再編集の機能を使えば、いくらでも変更が効きます。
これらは開発側も認識しているようなので、そのうち対策が入るかもしれません。
条件分岐のサポート
移行すべきかの議論で書いたように、今のところ、Issue formsでは条件分岐はできません。しかし、Issueテンプレートに複数のケースのテンプレートを含めておき、自分に該当するものだけ選んで入力し、後は消去してもらう、というやり方をしているフォームは実際に多少存在します。こういったものが扱えるようになるとよりよいですね。
バージョン
- GitHub Issue formsおよび仕様:2021年10月31日現在のもの
- Visual Studio Code: 1.61.2
参考資料
-
GitHub Docsの『Issue フォームの構文』
- Issue forms全体やトップレベル要素の文法についてはこちらを参照するとよいでしょう。
-
GitHub のフォームスキーマの構文』
- 各フォーム要素の文法(キー、値の型、必須/任意など)についてはこちらを参照してください。執筆時点では、英語版のほうが読みやすいかもしれません。
-
『Issues forms beta for public repositories』
- リリースアナウンスです。