GitLabのartifacts reportsを設定する

## 目的

こんにちは、Gakken LEAP のバックエンドエンジニアの mizuno です。
プロダクトの開発において、GitHub Actions で rubocop の結果が PR に表示されていて見やすいなと思っていました。
個人で開発するときは GitLab を使っており似たようなことができないかと調べたところ、[artifacts reports](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html) を設定することでテストやコード、セキュリティのレポートをマージリクエストで表示ができることがわかりました。
rails のプロダクトを使って無料でも使える `coverage_report` , `codequality` , `secret_detection` のレポート結果を表示してみます。

## coverage_report

### coverage の XML を出力する

`coverage_report` は rspec 実行することでテスト結果のカバレッジ率を表示することができるようになります。
coverage の設定は `spec_helper.rb`に以下を追記します。

```rb:spec_helper.rb
if ENV['CI']
  require 'simplecov'
  require 'simplecov-cobertura'
  SimpleCov.start do
    formatter SimpleCov::Formatter::CoberturaFormatter
  end
end
```

`ENV['CI']` で分岐することでパイプラインの実行時だけ coverage を出力するようにしています。
ファイルは `coverage/coverage.xml`に出力されます。

### junit フォーマットの XML を出力する

rspec を実行したときの引数に junit フォーマットと出力先を指定すると `junit.xml` が生成されます。

```sh
rspec --format RspecJunitFormatter --out coverage/junit.xml
```

`artifacts.reports.junit`に junit フォーマットの XML を指定することでレポート結果を表示することができるになります。

上記の出力した XML を設定した時の `.gitlab-ci.yml` は以下のようになります。

```yaml:.gitlab-ci.yml
.base:
  image: ruby:3.2.2
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - ${CI_PROJECT_DIR}/vendor/ruby
  before_script:
    - bundle config set path ${CI_PROJECT_DIR}/vendor/ruby
    - bundle config set --local test true
    - bundle install -j $(nproc)

# rspec
rspec:
  extends: .base
  stage: test
  services:
    - name: postgres:13.4
      alias: db
  script:
    - bundle exec ridgepole -c config/database.yml -E test --apply -f db/schemas/Schemafile
    - bundle exec rspec --format RspecJunitFormatter --out coverage/junit.xml
  coverage: '/\(\d+.\d+\%\) covered/'
  artifacts:
    reports:
      junit: coverage/junit.xml # 出力したファイルを指定
      coverage_report:
        coverage_format: cobertura
        path: coverage/coverage.xml # 出力したファイルを指定
```

:::note info
coverage に正規表現を入れると**リポジトリの分析**で**コードカバレッジの統計**に反映されます。
他のツールの正規表現は [test-coverage-examples](https://docs.gitlab.com/ee/ci/testing/code_coverage.html#test-coverage-examples) を参考
:::

## codequality

コード品質のイシューを収集します。

:::note info
codequality でチェックされる種類は [list-of-engines](https://docs.codeclimate.com/docs/list-of-engines) で確認できます。
:::

1. `.gitlab-ci.yml` に以下を記述します。

```yml:.gitlab-ci.yml
include:
  - template: Code-Quality.gitlab-ci.yml

code_quality:
  stage: test
  tags:
    - cq-sans-dind
```

※ [Code-Quality.gitlab-ci.yml](https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml) については GitLab が提供しているテンプレートになります。

2. private runner を設定

[improve-code-quality-performance-with-private-runners](https://docs.gitlab.com/ee/ci/testing/code_quality.html#improve-code-quality-performance-with-private-runners) にあるようにパフォーマンスを向上させるために private runner を設定します。

```sh
$ gitlab-runner register --executor "docker" \
  --docker-image="docker:latest" \
  --url "https://gitlab.com/" \
  --description "cq-sans-dind" \
  --tag-list "cq-sans-dind" \
  --locked="false" \
  --access-level="not_protected" \
  --docker-volumes "/cache" \
  --builds-dir "/tmp/builds" \
  --docker-volumes "/tmp/builds:/tmp/builds" \
  --docker-volumes "/var/run/docker.sock:/var/run/docker.sock" \
  --registration-token="<project_token>" \
  --non-interactive
```

### 実行時にエラーになりやすいポイント

#### 1. `/tmp/cc` がない

```sh
Bind mount failed: '/tmp/cc'
```

`/tmp/cc` をマウントしているようでフォルダを作成することでエラーが解消する。

#### 2. TargetRubyVersion が対応していない

`.rubocop.yml` の `TargetRubyVersion` に対応していないバージョンを選択しているとエラーになる。

```sh
error: (CC::CLI::Analyze::EngineFailure) engine rubocop failed with status 1 and stderr
/usr/local/bundle/gems/rubocop-0.92.0/lib/rubocop/config_validator.rb:83:in `check_target_ruby': RuboCop found unknown Ruby version 3.1 in `TargetRubyVersion` parameter (in .rubocop.yml). (RuboCop::ValidationError)
Supported versions: 2.4, 2.5, 2.6, 2.7, 3.0
```

サポートされているバージョンを選択することで解消される。

:::note warn
**codequality:0.96.0 ではサポートされている ruby のバージョンが 2.4, 2.5, 2.6, 2.7, 3.0**
:::

#### 3. config.toml の privileged が false になっている

`privileged` が `false` で設定されていると実行できない。
`true` にすることで実行することができる。

```toml
[[runners]]
  ...
  executor = "docker"
  [runners.docker]
    ...
    privileged = true
```

## secret_detection

リポジトリをスキャンし、シークレットの漏洩を防止します。

`.gitlab-ci.yml` に以下を記述します。

```yml:.gitlab-ci.yml
include:
  - template: Jobs/Secret-Detection.gitlab-ci.yml
```

### まとめ

![20240318_mizuno.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712998/3a9a6f98-39b8-1194-ae32-0d716751460c.jpeg)

画像のようにマージリクエストの概要で実行結果が表示されるようになり、パイプラインの詳細を確認しないでも簡単な結果が表示されるようになりました。
有料のプランでは他にも機能があり、表示される内容にも差があるので有料プランを使っている方はぜひ試してみてください。

Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています！！

https://gakken-leap.co.jp/recruit/