BIGLOBEの「はたらく人」と「トガッた技術」

「regist」を駆逐せよ!~reviewdogとDanger JS活用術~

reviewdogとDanger JSでコード内のスペルミスを発見し、修正を自動的に促す方法をご紹介します。

はじめに

こんにちは、プロダクト技術本部の小川です。

みなさんは「regist」という単語、見覚えがありますか? この単語を見ると、「それって"register"じゃないの?」と思いませんか? もしそう思ったなら、あなたが正しいです。「regist」は英語では存在せず、「register」が正しい表現です。
しかし、なぜか特に情報技術の世界では、無意識のうちに「regist」が使われることが多いです。プログラマーにとって、他人のコードを見る際に予想外のスペルミスを発見するというのは、理解を阻害し時間を無駄にする要因となります。

この記事では、reviewdogとDanger JSというツールを使用してそのようなスペルミスを発見し、自動的に修正を促す方法をご紹介します。 それでは、さっそく詳細について見ていきましょう。

「regist」という単語について

「regist」という単語は一般的に私たちが思い浮かべるような単語でしょうか?

実際にGoogleでその意味を検索してみましょう。  「regist」という単語の意味をGoogleで検索する

※ Google および Google ロゴは Google LLC の商標です。

ん?この単語の意味は「登録する」だと思っている人も多いのではないでしょうか。 「regist」という単語はコルシカ語だった

ってかコルシカ語って何?英語じゃないん?? 「登録する」を意味する正しい英単語は「register」です

そうなんです…!!実は「regist」という英単語は存在しないんです…!「登録する」を意味する正しい英単語は「register」なんです!!!!
これを誤解している方が多いように思います。6、7年ほどエンジニアとして働いてきましたがソースコード上に「登録する」という意味の単語として「regist」を使用する場面を数々見てきました。
読者のみなさんも見覚えがあるのではないでしょうか?ほら・・・いつも面倒を見ているソースコードにも・・・😇

私個人としては、「regist」という単語がソースコードに混じっていると大変気になってしまいます。意味が全く通じないというほどのものではないですが、タイポした単語がソースコードに残されることはコード全体の記述の統一性の点からみてもよろしいとは言えないでしょう。

そこで、「regist」をソースコードから「駆逐」してやりましょう。Danger JSとreviewdogを使って。

Danger JS について

Danger JSはコードレビューの効率化・自動化を行うためのツールです。特に「チーム内で慣習的に行われているコードレビューの自動化」を目的にしています。例えば以下のようなルールや内容を自動的にチェックし、プルリクエストのコメントとして自動投稿することができます。

  • リリースノートが作成されていること
  • プルリクエストのタイトルや本文が特定のルールに従った内容であること
  • プルリクエストにラベルが設定されていること
  • 特定のファイルが変更されていること

プルリクエストのメタデータを基に、Danger JSでルールを定義することで上記のようなコードレビューのルールが遵守されているかを検知することができます。

reviewdog について

reviewdogは、Linterなどのチェックツールの結果をGitHubのプルリクエストにコメントするためのツールです。プルリクエストで変更された内容にLinterのルールに違反する内容が含まれる場合に、reviewdogはLintの結果をコメントとして投稿をします。 ツールの作成にいたる背景などのより詳しい内容はreviewdog開発者様のブログをご参照ください。

プルリクエスト作成時に「regist」を検出し警告する

GitHub Actionsを使用して、プルリクエスト作成時にreviewdogとDanger JSを動かし、「regist」の存在をプルリクエスト内で検出します。そのために、リポジトリの.github/workflowsディレクトリにGitHub Actionsのワークフローを定義します。

Danger JSをGitHub Actionsで動かす設定

まず、GitHub Actionsのワークフローを定義します。リポジトリの.github/workflowsディレクトリにyamlファイルを作成します。

name: danger
on:
  - pull_request

jobs:
  build:
    name: Danger JS
    runs-on: ubuntu-latest
    permissions: write-all
    steps:
      - uses: actions/checkout@v3
      - name: Danger
        uses: danger/danger-js@11.0.2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          DANGER_DISABLE_TRANSPIRATION: true

次に、プロジェクトのルートディレクトリにのdangerfile.tsを作成します。 このファイルは、Danger JSが実行する際に読み込む設定ファイルです。

import { GitHubPRDSL, danger, markdown, warn } from "danger";

const findRegist = (content: string) => {
  return content.match(/\bregist\b/)
}

const warnRegist = (createdBy: string) => {
    const body = `

## 👮👮👮regist警察出動!!!👮👮👮
@${createdBy}  
⚠️⚠️⚠️ちょっとまってください!⚠️⚠️⚠️
もしかして、『**regist**』という単語を使おうとしていませんか??
『regist』という単語は**存在しません!!**
「登録する」という意味の英単語は『『『**register**』』』です!!!!以後、気をつけるように!!!

### 参考資料
+ [ソースコードの頻出単語 regist (覚えるべからず) | MSeeeeN](https://mseeeen.msen.jp/resist-regist/)
+ [“regist” という単語は存在しない | text.Baldanders.info](https://text.baldanders.info/remark/2017/04/regist-dose-not-exist/)
+ [regist 存在しない - Google 検索](https://www.google.com/search?q=regist+%E5%AD%98%E5%9C%A8%E3%81%97%E3%81%AA%E3%81%84&rlz=1C5CHFA_enJP1007JP1008&oq=regist+%E5%AD%98%E5%9C%A8%E3%81%97%E3%81%AA%E3%81%84&gs_lcrp=EgZjaHJvbWUyBggAEEUYOTIICAEQABgKGB7SAQgzMjYyajFqN6gCALACAA&sourceid=chrome&ie=UTF-8)`

    warn("Warning!!!")
    markdown(body)
}

const warnRegistInPullRequest = (pullRequest: GitHubPRDSL) => {
  const title = pullRequest.title
  const body = pullRequest.body
  const createdBy = pullRequest.user.login

  if (findRegist(title) || findRegist(body)) {
    warnRegist(createdBy)
  }
}

warnRegistInPullRequest(danger.github.pr)

Danger JSが実行される際、warnRegistInPullRequest関数が実行されます。 この関数は、プルリクエストのタイトルと本文の両方を findRegist 関数に渡して "regist" の存在をチェックし、もし存在した場合は warnRegist 関数を呼び出して警告メッセージを投稿します。

reviewdog を GitHub Actionsで動かす設定

こちらも同様にGitHub Actionsのワークフローを.github/workflowsディレクトリに定義します。

name: reviewdog

on:
  pull_request:
    branches:
      - "**"

jobs:
  reviewdog:
    runs-on: ubuntu-latest
    name: reviewdog
    permissions:
      pull-requests: write
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Set up JDK
        uses: actions/setup-java@v1
        with:
          java-version: 17
      - name: Download checkstyle
        run: wget -O - -q https://github.com/checkstyle/checkstyle/releases/download/checkstyle-10.12.6/checkstyle-10.12.6-all.jar > ./checkstyle.jar
      - name: Setup reviewdog
        run: |
          mkdir -p $HOME/bin && curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh| sh -s -- -b $HOME/bin
          echo "$HOME/bin" >> $GITHUB_PATH
      - name: Run reviewdog with checkstyle
        env:
          REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: java -jar checkstyle.jar -c ./checkstyle/checkstyle.xml ./ -f xml | reviewdog -f=checkstyle -reporter=github-pr-review

このワークフローでは、プルリクエストが作成されると、Checkstyleをダウンロードして実行し、その結果をreviewdogにパイプします。reviewdogはその結果をGitHubのプルリクエストに警告コメントとして投稿します。

<!DOCTYPE module PUBLIC
    "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
    "https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
    <module name="TreeWalker">
        <module name="Regexp">
            <property name="format" value="(^|\b|(?&lt;=[a-zA-Z\-_]))((R|r)egist)(\b|(?=[A-Z\-_])|$)|(^|\b|(?&lt;=[\-_]))REGIST(\b|(?=[\-_])|$)"/>
            <property name="illegalPattern" value="true"/>
            <message key="illegal.regexp" value="「regist」という単語が使用されています!!「登録する」という単語は「register」を使用してください!!"/>
        </module>
    </module>
</module>

Checkstyleの設定ファイルは上記の内容です。今回はcheckstyleというディレクトリをプロジェクトルートに作成し、checkstyle.xmlというファイル名で配置します。

プルリクエスト作成

たとえば、以下のように「createをregistに修正する」ような変更を含むプルリクエストを作成します。

public class Sample {
-    public static void create() {
-        var sample = "create is great!";
-        var PRE_CREATE_VALUE = "sample";
+    public static void regist() {
+        var sample = "Regist is great!";
+        var PRE_REGIST_VALUE = "sample";
         System.out.println(sample);
    }
}

createをregistに修正するプルリクエストを作成

Danger JSがプルリクエストのタイトルに含まれた『regist』という単語を検知します。

Danger JSが「regist」という単語を検知する

すると、このような おせっかいな コメントを残してくれます。

CheckstyleによるLintの結果をreviewdogがプルリクエストにコメント

また、CheckstyleによるLintの結果をreviewdogがプルリクエストにコメントとして残してくれます。 これで「regist」を駆逐できそうです。

reviewdogとDanger JSの使い分け

今回、reviewdogとDanger JSという2種類のツールを使用しました。これら二つは共にコードレビューを自動化するためのツールですが、それぞれのツールに異なる特徴があります。 reviewdogは様々なプログラミング言語の静的解析ツールと連携し、その結果を提供することができます。一方、Danger JSはGitやプルリクエストのメタデータ(コミットメッセージや変更されたファイル、プルリクエストの説明など)に基づきルールを設定し、フィードバックを提供します。例えば、「プルリクエストの説明がX文字以下であれば警告を出す」、「プルリクエストのタイトルに特定のフレーズが含まれていなければ警告を出す」といったルールを設定することで、プルリクエストの品質を一定以上に保つことができます。

したがって、静的解析結果を基にしたフィードバックが必要な場合はreviewdogを、プルリクエストのメタデータに基づいたルールが必要な場合はDanger JSを使用すると良いでしょう。

終わりに

reviewdogは自分が関わっているシステムでも組み込まれていて存在は知っていましたが、自分で1から設定して動かす機会は初めてであったため学びになりました。 またDanger JSは初めての導入でしたが、GitHub Actionsで動かすのにそれほど難しい設定もなく動かすことができたので、手軽さを知ることができました。 これからもチームの生産性向上に繋げられる活動を続けられればよいなと思っております。

ここまで読んでくださって、ありがとうございました!

参考

※ GitHubは、GitHub, Inc.の米国およびその他の国における商標または登録商標です。