GitHub の Release のリリースノートに含まれいてるプルリクエストのラベル一覧を取得する
リリース時にプルリクエストのラベルを使ってワークフローの処理変更しようと考えた。
当初予定では .github/release.yml
で特定のラベルに対応するカテゴリーを作成し、リリースノート内のカテゴリーの有無で判定しようと思っていた。
changelog:
categories:
- title: Features
labels:
- enhancement
- title: Types Changes
labels:
- types
- title: Bug Fixes
labels:
- bug
- title: Other Changes
labels:
- '*'
しかし、プルリクエストに複数のラベルがセットされている場合、最初に一致したカテゴリーのみに反応するという仕様だったの。
よって、enhancement
と types
がセットされていると Features
カテゴリーのみ表示されるようになる。
この場合、Types Changes
があったらワークフローを実行させるという用途への利用は難しい。
対応策としては Types Changes
を先頭にもっていく方法もあるが、表示上は Features
を優先させたい。
まず、自前でタグ間のプルリクエストの一覧を取得しようと思ったが、これは難しいので今回はパス。
リリースノートにプルリクエストのリンクがあるのでこれを利用する。
元は Markdown で記述されているので remark-cli で切り出そうかと思ったが、Markdown だと URL がベタ書きされているだけなので remark-gfm などが必要になる。
GraphQL API だと descriptionHTML
で HTML 版が取得できる。
$ gh api graphql --jq .data.repository.release.descriptionHTML -F owner='{owner}' -F name='{repo}' -f query=' { repository(owner: "hankei6km", name: "gas-md2html") { release(tagName:"v0.5.0"){ descriptionHTML } } }'
<h2>What's Changed</h2>
<ul>
<li>Setup by <a class="user-mention" data-hovercard-type="user" data-hovercard-url="/users/hankei6km/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/hankei6km">@hankei6km</a> in <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1108312729" data-permission-text="Title is private" data-url="https://github.com/hankei6km/gas-md2html/issues/1" data-hovercard-type="pull_request" data-hovercard-url="/hankei6km/gas-md2html/pull/1/hovercard" href="https://github.com/hankei6km/gas-md2html/pull/1">#1</a></li>
この query はリポジトリ名が書き込まれたものをコピペしたので汎用的には使えない。
rehype-cli で tree にする。
$ gh api graphql --jq .data.repository.release.descriptionHTML -F owner='{owner}' -F name='{repo}' -f query=' { repository(owner: "hankei6km", name: "gas-md2html") { release(tagName:"v0.5.0"){ descriptionHTML } } }' | npx --package=rehype-cli rehype -S --tree-out | less
{
"type": "root",
"children": [
{
"type": "element",
"tagName": "html",
"properties": {},
"children": [
{
"type": "element",
"tagName": "head",
"properties": {},
"children": []
},
{
"type": "element",
"tagName": "body",
"properties": {},
"children": [
{
jq でプルリクエストの番号一覧にする(重複を取り除く)
$ gh api graphql --jq .data.repository.release.descriptionHTML -F owner='{owner}' -F name='{repo}' -f query=' { repository(owner: "hankei6km", name: "gas-md2html") { release(tagName:"v0.5.0"){ descriptionHTML } } }' | npx --package=rehype-cli rehype -S --tree-out | jq -r 'map(..) | .[] | select(type=="object") | select(.tagName=="a") | .properties.href | select(contains("/pull/")) | split("/") | .[-1] ' | sort | uniq
1
2
3
4
5
6
7
8
プルリクエストからラベル一覧を取得する
$ gh api graphql --jq .data.repository.release.descriptionHTML -F owner='{owner}' -F name='{repo}' -f query=' { repository(owner: "hankei6km", name: "gas-md2html") { release(tagName:"v0.5.0"){ descriptionHTML } } }' | npx --package=rehype-cli rehype -S --tree-out | jq -r 'map(..) | .[] | select(type=="object") | select(.tagName=="a") | .properties.href | select(contains("/pull/")) | split("/") | .[-1] ' | sort | uniq | while read -r PR ; do gh api "repos/{owner}/{repo}/pulls/${PR}" --jq .labels[].name ; done | sort | uniq
enhancement
refactoring
testing
ワークフローの中で使おうと思うと Node.js の実行環境が必要になるのがちょっと面倒かな。
とりあえず目的のものはできたのでクローズ。
ubuntu-latest
の Node.js が 16.x でとくに設定しなくてもよさそうだったので
ワークフローで使ってみた。
ジョブをわけておけば job.<job_id>.if
などで使える。
が、これを毎回書くのは面倒。
Action にした方がよいのかな。
jobs:
labels_from_rel_note:
runs-on: ubuntu-latest
outputs:
labels: ${{ steps.get.outputs.labels }}
steps:
- name: Collect Labels from release note
id: get
# REPOSITORY は OWNER と NAME に分割する.
# jq のときは環境変数でないとアクセスできないので REPOSITORY を使う.
# label の一覧は複数行になっているので set-output に収まるようにエンコードしている.
# https://github.community/t/set-output-truncates-multiline-strings/16852/3
run: >-
OWNER="$(cut -d '/' -f 1 <<< ${REPOSITORY})";
NAME="$(cut -d '/' -f 2 <<< ${REPOSITORY})";
LABELS="$(
gh api graphql --jq .data.repository.release.descriptionHTML -F owner="${OWNER}" -F name="${NAME}" -F tag_name="${TAG_NAME}" -f query='
query ($owner: String!, $name: String!, $tag_name: String!) {
repository(owner:$owner, name:$name) {
release(tagName:$tag_name){
descriptionHTML
}
}
}'
| npx --package=rehype-cli rehype -S --tree-out
| jq -r 'map(..) | .[] | select(type=="object") | select(.tagName=="a") | .properties.href | select(contains("https://github.com/" + env.REPOSITORY + "/pull/")) | split("/") | .[-1] '\
| sort | uniq
| while read -r PR ;
do gh api "repos/${OWNER}/${NAME}/pulls/${PR}" --jq .labels[].name ;
done | sort | uniq
)" ;
LABELS="${LABELS//'%'/'%25'}" ;
LABELS="${LABELS//$'\n'/'%0A'}" ;
LABELS="${LABELS//$'\r'/'%0D'}" ;
echo "::set-output name=labels::${LABELS}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPOSITORY: ${{ github.repository }}
TAG_NAME: ${{ github.event.release.tag_name }}
print_labels:
needs: labels_from_rel_note
runs-on: ubuntu-latest
steps:
- run: echo "${{ needs.labels_from_rel_note.outputs.labels }}"