Node-REDのGit機能を学ぶ(7) フローの静的解析

　本記事は「Node-REDのGit機能を学ぶハンズオン(第3回)」で紹介した内容です。

https://youtu.be/faU7qmTtFgk?feature=shared&t=3617

　本記事ではGitHub Actionsを用いたフローの静的解析の手順について紹介します。
　Node-REDのフロー開発はノードをつないでゆくのみのため、コーディングによる開発と比較するとタイポなどによる不良は発生しにくいのですが、それでも問題が起きることがあります。多くの場合、それはNode-REDに関する知識不足があったり、チーム固有のルールが規定されていなかったりすることで、独自の開発方法で作り込んでしまうことから生じています。例えば、Node-REDを用いたチーム開発を経験した方は、以下の様なケースを見かけたことがあるでしょう。

## 問題1: フローに無限ループが存在
　意図的にループにしている場合は問題ありませんが、仕様を知らずにフローをループさせてしまうと無限ループが発生することがあります。特に、linkノードを多用すると、気づかないうちに視覚的に見えない無限ループを作ってしまうことがあります。

## 問題2: http in、http responseノードが組になっていないHTTPエンドポイント
　Node-REDでHTTPのエンドポイントを作成するには、http-inノードで始め、フローの終端に置いたhttp responseノードからHTTPの応答を返す必要があります。HTMLを返す場合はブラウザで動作確認するため、http responseノードが必要なことにすぐ気づきます。一方、Webhookのエンドポイントを作る場合、http-inノードからメッセージを受け取り処理するだけのフローを作っただけで、http responseノードを置かなくても動いてしまうため、問題に気づかないことがあります。

## 問題3: functionノードのJavaScriptコードに一貫性がない
　functionノードは自由にJavaScriptのコードを記載できるため、複雑な実装をしたり、標準ノードの実装より処理性能を向上させたりしたい場合に有効です。ただ、自由度が高いことでフロー開発者独自の実装になりがちです。一般的なコーディングと同じ様にESLintで、JavaScriptのコーディングルールを規定しておきたいというケースはあるでしょう。

## 問題4: ノードの名前をローカル言語で記載してしまう
　Node-REDのフローエディタは日本語化されているため、自然とノードの名前に日本語を使ってしまいがちなのですが、海外のオフショア開発などでグローバルチームで開発する際に英語以外の言語を使ってしまうと、日本以外のメンバは読むことができません。日本語を読むより開発した方が早いとなり、同じ機能を二重開発してしまった等は良くある話です。

　これらは些細な問題ですが、大規模開発では小さな不具合が積もり、後々大きな問題になってくることがあるかもしれません。これらの問題をなるべく避けて、スムーズに開発を進めたいと思うでしょう。

# フローリンターとは
　前述した様な状況を無くすためにNode-REDの公式プロジェクトでは、バグが生じる可能性のあるフローの作成方法に対して、警告を表示してくれる「フローリンター」というプラグインを提供しています。フローリンターは「Node-REDにプラグインとしてインストールしてフローエディタで利用する方法」と、「Node-REDとは別に単体でコマンドラインから利用する方法」の2種類の利用方法があります。
　次のスクリーンショットは、フローリンタをインストールした後のNode-REDフローエディタの画面です。フローにループが存在しているため、ループを作っているノードの右上に「！」マークが付いています。また「リント」タブには「loop detected」という警告の内容が表示されています。

![フローリンターがループの警告を表示.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/bf358f6a-fcfb-1fcc-0142-aa88f14f1f7c.png)

　フローエディタでのフローリンターの利用方法ついて知りたい方は、下記「Node-RED影の薄い機能特集！」という勉強会の動画を視聴してみてください。

https://node-red.connpass.com/event/293534/

　本動画では、前述した「ノードの名前をローカル言語で記載してしまう」の問題を警告するカスタムルールの作り方についても触れています。
　ここからフローリンターをGitHub Actionsに組み込んで利用する方法を解説します。

## GitHubリポジトリの作成

https://github.com/new

　上記のURLから「node-red-api」というリポジトリを作成しましょう。

![Screenshot 2024-04-25 at 0.07.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/d390b549-b55f-dc26-0f25-c970a9c4af8f.png)

　リポジトリの公開設定は、Privateにします。

## Node-REDからREST APIのフローをアップロード

![Screenshot 2024-04-26 at 0.13.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/c7a6f552-acdd-2bd4-684b-5d18c1f25e01.png)

上記のREST APIのフローを作成し、「はじめてのAPI」というコミットメッセージをつけてGitHubリポジトリにアップロードします。

![Screenshot 2024-04-26 at 0.15.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/9658a187-5edd-e97f-3b11-67f087cadb8f.png)

## GitHub Actionsにフローリンターを設定
　次に、フローリンターの実行に必要な設定ファイル「.nrlintrc.js」を作成します。複製したGitHubリポジトリの画面にある「+」ボタンをクリックし、メニューの中の「Create new file」を選択します。

![Screenshot 2024-04-26 at 0.18.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/56ccd20c-efe7-8d87-7544-044411cca636.png)

## フローリンターの設定ファイル「.nrlintrc.js」を作成
　次のGitHubのファイル編集画面では、新規に作成するファイル名として「.nrlintrc.js」、ファイルの内容は下記を記載します。

```JavaScript
module.exports = {
    "rules": {
        "align-to-grid": true,
        "max-flow-size": true,
        "no-duplicate-http-in-urls": true,
        "no-loops": true,
        "no-overlapping-nodes": true,
        "no-unconnected-http-nodes": true,
        "no-unnamed-functions": true,
        "no-unnamed-links": true
    }
}
```

![Screenshot 2024-04-25 at 0.39.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/2168914f-0238-7954-43f7-57d96d1ce1a2.png)

記載した後は、右上の緑ボタン「Commit Changes」をクリックし、内容をGitHubリポジトリに反映させます。

# フローリンターで設定できるルール
　フローリンターには、次の表の様なNode-REDのビジュアルプログラミングならではルールが8種類、デフォルトで用意されています。ここでは全てのルールを有効にしました。

| # | ルール | 説明 |
|---|------------|------------|
| 1 | align-to-grid | ノードをワークスペースの格子に合わせる |
| 2 | max-flow-size  | フロー内のノードの上限数(デフォルト:100個) |
| 3 | no-duplicate-http-in-urls | http-inに設定したURLの重複を警告 |
| 4 | no-loops | フローのループを検出 |
| 5 | no-overlapping-nodes | ノードが重なりを検出 |
| 6 | no-unconnected-http-nodes | http-in、http responseがペアになっているか |
| 7 | no-unnamed-functions | functionノードに名前が付けられているか |
| 8 | no-unnamed-links | linkノードに名前が付けられているか |

　もしfunctionノードに適用できるESLintのルールを設定したい場合は、次の様に設定ファイルに「function-eslint」のセクションを追加します。

```JavaScript
module.exports = {
    "rules": {
        "align-to-grid": true,
        … 省略 …
        "no-unnamed-links": true,
        "function-eslint": {
            "config": {
                "env": {
                    "es2021": true
                },
                "parserOptions": {
                    "ecmaVersion": 12
                },
                "rules": {
                    "constructor-super": "error",
                    "for-direction": "error",
                    … 省略 …
                    "use-isnan": "error",
                    "valid-typeof": "error"
                }
            }
        }
    }
}
```

これらESLintの設定項目については、次の公式ドキュメントを参照してください。

https://eslint.org/docs/latest/rules/

　次に、GitHub Actionsの設定をするため、GitHubリポジトリのActionsタブをクリックします。今回は独自に設定ファイルを記載するため、その中の「set up a workflow yourself」をクリックします。

![Screenshot 2024-04-26 at 0.21.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/36812a48-83ad-241a-4bfd-cdadd5cdddcf.png)

 `.github/workflows/main.yml`に下記内容を記載します。

```
name: nrlint

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-node@v3
    - run: npm install -g nrlint
    - run: nrlint flows.json
```

![Screenshot 2024-04-26 at 0.24.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/7579a6a3-5281-cebb-17f5-edb2c78be987.png)

# GitHub Actionsが実行されていることを確認
　右上にある「Commit Changes」ボタンをクリックすると、GitHub Actionsが動き出します。動作状況を確認するため、GitHubリポジトリのActionsタブを選択しましょう。以下の様にGitHub Actionsが実行されているはずです。

![Screenshot 2024-04-26 at 0.25.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/c14c0393-8cb3-bf1a-fdfe-888b4a2ad0ab.png)

　表示された項目をクリックしてゆくと、コマンドのログを確認できる画面に遷移できます。実行してから1分ほど経過すると、緑色のチェックマークになり成功したことが分かります。
 
 ![Screenshot 2024-04-26 at 0.25.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/59352b45-1151-4189-c569-c48f280208df.png)

# 正常でないフローをアップロード
　次に以下のようなhttp inノードとhttp responseノードがワイヤーで繋がれていないフローを作成し、GitHubリポジトリにアップロードしてみます。

 ![Screenshot 2024-04-26 at 0.29.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/a64b7012-1b3a-d62d-32e2-250cbe623464.png)

アップロードするとすぐにGitHub Acitonsが動きだし、エラーのコミットとなるでしょう。

![Screenshot 2024-04-26 at 0.30.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/5539eefb-b75f-f008-6dcd-d9a15b18d5c5.png)

中のログを確認すると、「HTTP In node does not reach an HTTP Response node」と「Unconnected HTTP Response node」というエラーが表示されており、http inノードとhttp responseノードがうまく接続されていないことが分かります。

![Screenshot 2024-04-26 at 0.31.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287766/a12f6b24-1487-b6b5-c330-d8b11d5a9f97.png)

# 最後に
　フローリンターを用いることで、開発チームの暗黙のルールを設定ファイルに明記でき、後からチームに参加するメンバも開発ルールに沿っていない場合に自身で気づくことができるようになります。フローリンターの設定は、チームでフローを開発する際に、必須のリポジトリ設定ですので覚えておくと良いでしょう。