2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【カバレッジ警察出動】GitHub Actionsでカバレッジをチェック → 保護ルールでマージ制限してみた

Posted at

はじめに

pushやcommit前にテストの実行などを強制するツールに、huskyやlint stagedなどがあります。

これらは有用で良い感じなのですが、ローカルに閉じてしまう仕組みです。
チーム開発においては「誰がどこで詰まってるか?」といった状況が見えづらいのが難点です。

「テストやカバレッジをクラウド上(CI)で検証し、その結果をGitHub上で自動的に可視化・共有できたら便利だな~」 と思い、今回の取り組みを試してみました。

今回の構成

9739e5de-ddc4-4a31-bc35-c89fb4c14d44.png

今回の構成です。

  1. GitHub ActionsでCIを構成し、ブランチにpushされたタイミングでカバレッジをチェックするテストを実行します
  2. GitHubのブランチ保護ルールを使い、mainブランチへのPRが“上記のテストにパスしていること”を必須条件とします
  3. たぶん良い感じになるはずです

準備

コードを用意する

こんな感じのプロジェクトを用意します。細かい部分は以下で補足します。

github-action-hello-world
  ├── _test_
  │   └── math.test.ts
  │
  ├── .github
  │   └── workflows
  │       └── node.js.yml
  │
  ├── node_modules
  │
  ├── src
  │   └── math.ts
  │
  ├── .gitignore
  ├── package-lock.json
  ├── package.json
  ├── README.md
  ├── tsconfig.json
  └── vitest.config.ts

Vitest(Nodejs)でテストコード用意

本筋ではないので適当に用意します。

src/math.ts
テスト対象コードです。3つの関数を持ちます。

src/math.ts
export function add(a: number, b: number): number {
    return a + b
}

export function subtract(a: number, b: number): number {
    return a - b
}

export function multiply(a: number, b: number): number {
    return a * b
}

test/math.test.ts
テストコードです。src/math.ts 内の関数をテストしますが、意図的にカバレッジを下げています。

__test__/math.test.ts
import { describe, it, expect } from 'vitest'
import { add, multiply } from '../src/math'

describe('math functions', () => {
    it('adds two numbers', () => {
        expect(add(2, 3)).toBe(5)
    })

    it('multiplies two numbers', () => {
        expect(multiply(4, 5)).toBe(20)
    })
})

vitest.config.ts
今回使用しているテスティングライブラリの設定ファイルです。

vitest.config.ts
/// <reference types="vitest" />
import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    globals: true,       // describe, it, expect をグローバルに使えるように
    environment: 'node', // または 'jsdom'(ブラウザをエミュレートする場合)
    coverage: {
      reporter: ['text', 'json', 'html'],
      thresholds: {
        functions: 90,
      }
    },
  },
})

細かいところは無視して、大丈夫です。
カバレッジに関数網羅率90%を設定している、以下の部分が大事です!

      thresholds: {
        functions: 90,
      }

その他設定ファイルです。

設定ファイル
package.json
{
  "name": "vitest-sample",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "test": "vitest",
    "coverage": "vitest run --coverage"
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "vitest": "^3.1.1",
    "@vitest/coverage-v8": "^3.1.1"
  }
}
tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "Node",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "types": [
      "vitest/globals"
    ],
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ]
    }
  },
  "include": [
    "src",
    "tests"
  ]
}

カバレッジを測定してみる

npm run coverage でvitestを実行します

$ npm run coverage

> vitest-sample@1.0.0 coverage
> vitest run --coverage


 RUN  v3.1.1 /mnt/c/work/repo/github-action-hello-world
      Coverage enabled with v8

 ✓ __test__/math.test.ts (2 tests) 10ms
   ✓ math functions > adds two numbers 5ms
   ✓ math functions > multiplies two numbers 1ms

 Test Files  1 passed (1)
      Tests  2 passed (2)
   Start at  11:49:43
   Duration  6.91s (transform 510ms, setup 0ms, collect 541ms, tests 10ms, environment 1ms, prepare 3.55s)
 % Coverage report from v8
----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   77.77 |      100 |   66.66 |   77.77 | 
 math.ts  |   77.77 |      100 |   66.66 |   77.77 | 6-7
----------|---------|----------|---------|---------|-------------------
ERROR: Coverage for functions (66.66%) does not meet global threshold (90%)

ERROR: Coverage for functions (66.66%) does not meet global threshold (90%)

良い感じですね

GitHub Actions用のymlを作成する

.github/workflows/coverage.yml を作成します
ここらへんを参考に作成しました

.github/workflows/coverage.yml
name: check-coverage

on:
  push:
    branches:
      - main
      - develop

jobs:
  coverage:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Use Node.js 22.x
      uses: actions/setup-node@v4
      with:
        node-version: '22.x'
        cache: 'npm'
    - run: npm ci
    - run: npm run coverage

特にコメントがない普通?のymlです
Node22を使用しています

gitにpushしてみる

$ git push
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To github.com:suiwave/github-action-hello-world.git
   2945d1a..ba771a7  develop -> develop

いざpush!

cap1.PNG

GitHub上で確認します

cap2.PNG

良い感じに落ちてますね

cap3.PNG

developからmainにプルリクを作成してみました
当然、マージできてしまいます。危険!

Githubでブランチに保護ルールを設定する

GitHub Actionsでカバレッジをチェックできるようになりました
しかし、チェックがfailでもマージ可能であることも同時に確認できました
よくないので、ブランチ保護ルールで保護します!!

保護ルールを設定する

設定タブに移動

cap4.PNG

移動します

Branch設定に移動

cap4_5 - コピー.PNG

移動します。ドキュメントへのリンクもありますね。

ブランチルールセットを追加する

cap4_5 - コピー (2).PNG

「Add branch ruleset」をクリックします

ルールセット名とルールの有効化を設定する

cap5.PNG

ルールセット名は適当に「Require coverage checks to pass」
Enforcement statusを「Active」に設定し、ルールを有効化します

バイパスリストと対象ブランチを設定する

cap6.PNG

検証なのでバイパスリストは空としておきます
対象ブランチは、ルールで守るブランチを指定します
今回はマージを取り込むブランチであるdefaultブランチを指定します

Branch rulesを設定する

cap7.PNG

いろいろありますね
今回のルールセットは、Coverageのパスのみを要求するものなので、いったんすべてのチェックをオフにします
(直push禁止などは他のルールセットで設定する想定です)

Require status checks to passを設定する

cap8.PNG

Branch rulesの中の、Require status checks to passが今回追加するルールです

コミットはまずチェックが通る別の参照にプッシュされなければなりません。

mainブランチの更新は、チェックをパスしたブランチのプルリクで行いなさい、的な意味です(た、たぶん・・・)

追加設定を行う

cap9.PNG

「Require branches to be up to date before merging」のチェックもしておきます。基本ですね
また、Add checksから、作成したGitHubActionsのJobを選択します

ルールセットを作成する

cap10.PNG

再度設定内容を確認後、「create」をクリックします

喜ぶ

cap11.PNG

やったールールセットが作成されました
これで、プルリクマージ前に、カバレッジチェックのpassを必須とすることができました。

検証

状況確認

先ほどマージ可能だったプルリクを見に行きます

cap12.PNG

きたーーーーーーーーーーーーーーーーーーー

Merging is blocked due to failing merge requirements

良い感じですね

パスするブランチを作成してみる

パスするブランチも作ってみます。そこからプルリクをなげます

ブランチ作成

develop からfeature/remove-subtract-function ブランチを生やしてみます

$ git checkout -b feature/remove-subtract-function
Switched to a new branch 'feature/remove-subtract-function'

ファイル編集

src/math.ts
テストしていない関数を削除します(テストを増やせよ)

export function add(a: number, b: number): number {
    return a + b
}

- export function subtract(a: number, b: number): number {
-     return a - b
- }

export function multiply(a: number, b: number): number {
    return a * b
}

.github/workflows/coverage.yml
対象ブランチを拡張します

on:
  push:
    branches:
      - main
      - develop
+      - feature/*

push結果確認

pushしてGitHubActionsが実行されたことを確認します

cap13.PNG

きた!無事、対象ブランチが拡張され、またカバレッジチェックもpassしています

プルリク作ってマージできるか確認

プルリクつくって、確認します

cap14.PNG

はい、チェックパスしてるので、マージ可能です!
ブランチ保護ルールがしっかり働いていそうですね!

感想

9739e5de-ddc4-4a31-bc35-c89fb4c14d47.png

普段はCodeCommitやCodebuild,CodepipelineでCI/CDをしているのですが、なんとなくGitHub Actionsに入門してみました。

まずはゆるくCI前のプルリクフェーズで使ってみました。慣れるとActions実行結果画面のUIが良い感じで、良いなと感じました!
CI/CDワークフローなどもおいおい勉強したいです。

今回のリポジトリ

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?