Open9

GitHub の Release のリリースノートに含まれいてるプルリクエストのラベル一覧を取得する

hankei6kmhankei6km

リリース時にプルリクエストのラベルを使ってワークフローの処理変更しようと考えた。

当初予定では .github/release.yml で特定のラベルに対応するカテゴリーを作成し、リリースノート内のカテゴリーの有無で判定しようと思っていた。

release.yml
changelog:
  categories:
    - title: Features
      labels:
        - enhancement
    - title: Types Changes
      labels:
        - types
    - title: Bug Fixes
      labels:
        - bug
    - title: Other Changes
      labels:
        - '*'

しかし、プルリクエストに複数のラベルがセットされている場合、最初に一致したカテゴリーのみに反応するという仕様だったの。

よって、enhancementtypes がセットされていると Features カテゴリーのみ表示されるようになる。

この場合、Types Changes があったらワークフローを実行させるという用途への利用は難しい。

対応策としては Types Changes を先頭にもっていく方法もあるが、表示上は Features を優先させたい。

hankei6kmhankei6km

まず、自前でタグ間のプルリクエストの一覧を取得しようと思ったが、これは難しいので今回はパス。

hankei6kmhankei6km

リリースノートにプルリクエストのリンクがあるのでこれを利用する。

リリースノートでプルリクエストのリンクが表示されているスクリーンショット

元は 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>
hankei6kmhankei6km

この query はリポジトリ名が書き込まれたものをコピペしたので汎用的には使えない。

hankei6kmhankei6km

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": [
            {

hankei6kmhankei6km

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
hankei6kmhankei6km

プルリクエストからラベル一覧を取得する

$ 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
hankei6kmhankei6km

ワークフローの中で使おうと思うと Node.js の実行環境が必要になるのがちょっと面倒かな。

とりあえず目的のものはできたのでクローズ。

hankei6kmhankei6km

ubuntu-latest の Node.js が 16.x でとくに設定しなくてもよさそうだったので
ワークフローで使ってみた。

ジョブをわけておけば job.<job_id>.if などで使える。

が、これを毎回書くのは面倒。
Action にした方がよいのかな。

types.ymal
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 }}"