🔬

GitHub Actions で .NETプロジェクトの静的コード解析を行う

2021/01/27に公開

GitHubにコードをpushすると静的コード解析を走らせて、問題を指摘してくれるようなCI (GitHub Actionsのワークフロー)を作ります。

完成図

静的コード解析について

本記事ではMicrosoftが用意している解析機を使います。従来はFxCop analyzersと呼ばれていたもので、今は .NET analyzers というそうです。

使用する技術

使うのは dotnet build だけです。その他特別な第三者のツールは不要です。

言い換えると、本記事で対象にできるのは dotnet build でビルドできるプロジェクトです。古い .NET Framework のプロジェクト等ではひと手間必要かと思います。

類似の技術

本記事では使いませんが、ちなみにそのほかの類似の技術として以下のようなものがあります。

手順

ワークフロー定義

.github/workflows/<好きな名前>.yml というファイルを作成します。内容は素朴にビルドしているだけです。発動するのはpull requestを開いたときや、その後pushしたときになっています。

actions/setup-dotnet のREADMEにある registering problem matchers for error output のところが今回の肝になっているようです。
詳細:https://github.com/actions/toolkit/blob/master/docs/problem-matchers.md

.github/workflows/dotnet.yml
name: .NET

on:
  pull_request:
    types: [synchronize, opened]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Setup .NET
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 5.0.101

    - name: Restore
      run: |
        dotnet restore

    - name: Build
      run: |
        dotnet build --no-restore -warnaserror -clp:NoSummary

[追記] dotnet buildのパラメータに-clp:NoSummaryを付け加えることをお勧めします。 https://zenn.dev/shimat/articles/e6af698fca3fba

ソースコード

上記ワークフローの効きを確かめるため、適当な.NETプロジェクトを作ります。

雛形ほぼそのままの.NET5のコンソールアプリケーションです。警告を見たいので、ツッコミどころがあるクラスを入れています (こちらから参照)。

Program.cs
using System;

namespace ConsoleApp1
{
    public class demo : Exception
    {
        public static void Initialize(int size) { }
        protected static readonly int _item;
        public static int item { get { return _item; } }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}
ConsoleApp1.csproj
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <AnalysisMode>All</AnalysisMode>
  </PropertyGroup>

</Project>

この状態で、筆者の手元 (Visual Studio Professional 2019 Version 16.8.4) では、以下のような警告が出ています。これがGitHub上でも出てくれることを期待します。AnalysisMode: All により、素の状態よりもかなり込み入った警告が出ていることを確認しましょう。

フレームワークやVisual Studioが古い場合

このページを参考にします。 https://docs.microsoft.com/ja-jp/visualstudio/code-quality/install-net-analyzers?view=vs-2019

Microsoft.CodeAnalysis.FxCopAnalyzers のNuGetパッケージをインストールするのが早いと思います。
https://www.nuget.org/packages/Microsoft.CodeAnalysis.FxCopAnalyzers/

動作確認

ワークフローのYAMLを設定したリポジトリで、pull requestを作りましょう。以下は私が試した例です。

dotnet build -warnaserror のように -warnaserror オプションを付けたので、警告がエラーとして扱われています (参考)。

エラーではなく警告にする場合

ビルドのオプションから /warnaserror を取り除いた場合は警告となります。

GitHubのステータスは ✅ になるので、一見すると問題があるかどうか伝わりにくいです。厳格に警告0を目指すか、さりげないチェックにとどめるか、姿勢次第で考えてよいと思います。

もし指摘は警告で、かつGitHubの方のステータスは❌にしたいなら、dotnet buildからの出力に警告があるかどうかを自前で読み取って exit 1 すれば実現できそうです。それ以外にもpull requestのフィードへコメントしたり、Slack等へ通知したりしてもいいですし、いかようにも調整できます。

Windowsのワークフローの場合

runs-on: windows-latest としてWindows仮想環境でワークフローを記述した場合、同じYAMLでほとんど完全に動きますが、-warnaserror が効かないようです。

正確には、コマンドとしては意図通りエラーになるのですが、GitHub Actionsのワークフローはエラーにならず正常終了し、ステータスが ✅ になります。dotnetコマンドのステータスコードが0になっている模様?

ubuntu-latest と挙動が違うのがよくわかっていません。

課題

  • 今後pull requestを出したとき、そのときの差分ではない箇所にも指摘されてしまいます。従って、一度出た警告は全て対策していく姿勢が必要だと思います。意図したコードであって修正したくない場合は、例えば #pragma warning disable CA1032 のようにして抑止することができます。ビルドコマンドや.csprojへの設定等でも可能でしょう。なおGitHubはbeta機能として、今回の差分ではない箇所へのannotationも表示してくれます。
  • 警告の数が多いと、全部はdiffの中に表示されないようです。diffへのコメントはGitHub Checks API のannotation機能によって行われていますが、数に上限があるようです。たくさん出たなあと思ったら、持ち帰って手元で一括対策しましょう。
  • iOSやAndroidのGitHubアプリでは、annotationが表示されないようです。

まとめ

  • ごく簡単なGitHub Actionsワークフローによって、静的コード解析とコード挿入型の指摘が実現できます。
  • 一般には.NETのワークフローではテスト・NuGetパッケージの作成・何らかのデプロイなどを目指すと思います。その過程でdotnet buildはだいたい走らせることになりますから、本記事の内容は無意識のうちに実現できます。CI/CDはGitHub Actionsを使いましょうという結論です。
  • .NET界隈は、他言語と比べてチームメンバ各々の開発環境が均一である可能性が高い (だいたいVisual Studio) と考えられますが、それでも案外みな違うものです。コードレビューすると「これ警告出るはずなのに、どうしてそのままにしてるんだろう」と思うことはしばしばで、そのような環境でのコード品質改善に役立つかもしれません。

Discussion