Jenkins 也可與 .NET Core 搭配實現持續整合

在使用 TDD 開發時,儘管單元測試執行速度較快,但可能僅執行一部分的單元測試而已;而整合測試與驗收測試更慢,實務上不可能真的花時間去等待測試結果,而是希望在背景不斷地執行,在本機配合 Docker 執行 Jenkins 後,只要每次有新的 commit,就會自動執行所有測試,並將測試結果傳送到 Slack。

Version


macOS High Sierra 10.13.3
Docker for Mac 17.20.0-ce-mac49 (21995)
.NET Core 2.1.4
Jenkins 2.89.4
Slack 3.0.5
Rider 2017.3.1

User Story


我們希望每次 git push 到 Git 後,Jenkins 就會自動跑 Unit Test,若失敗則會通知 Slack。

Task


  • Git 直接使用本機的 git repository
  • Jenkins 使用本機的 Docker
  • Slack 可裝在本機或行動裝置

建立 .NET Core 專案


NumberService.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace NumberLib
{
public class NumberService
{
public bool isEven(int value)
{

if (value % 2 == 1)
{
return false;
}

return true;
}
}
}

isEven() 若為偶數傳回 true ,奇數傳回 false

slack000

NuberServiceTest.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using NumberLib;
using Xunit;

namespace NumberLibTest
{
public class NumberServiceTest
{
private readonly NumberService _numberService = new NumberService();

[Fact]
public void ShouldReturnTrueGivenEvenValue()
{

var result = _numberService.isEven(2);
Assert.True(result, "2 should return true");
}

[Fact]
public void ShouldReturnFalseGivenOddValue()
{

var result = _numberService.isEven(1);
Assert.False(result, "1 should return false");
}
}
}

提供兩個測試案例,分別測試傳回 truefalse

slack001

執行 Unit Test


slack002

直接在 Rider 執行單元測試,確認結果正確。

建立 Git Repository


要實現持續整合,Git 是其中的關鍵,唯有透過版控,才能在每個版本的變動觸發 Jenkins 自動執行測試。

slack003

直接在 Rider 建立 Git repository。

設定 Jenkins


建立與執行 Jenkins Container

若要 macOS 執行 Jenkins,最簡單的方法是透過 Docker,但只使用官方的 Jenkins image 是不夠的,因為我們必須在 Jenkins 的 Linux 環境跑單元測試,也就是說 Linux 必須要有 .NET Core SDK 環境。1 1關於建立 image 建立,詳細請參考 如何建立含有 .NET Core SDK 的 Jenkins Docker Image ?

1
$ docker run --name MyJenkinsCore -p 8080:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home -v /Users/oomusou/Code:/var/code   oomusou/jenkins-core

在建立 container 時,較特別的為

1
-v /Users/oomusou/Code:/var/code

-v 是設定 host os 的目錄,相當於 container 內對應的目錄。

如此就能使用 macOS 的開發工具,如 Rider 在 /Users/oomusou/Code,但 Jenkins 跑單元測試時是在 Linux 的 /var/code 目錄下。

Manage Jenkins

slack004

  1. 左側選 Manage Jenkins
  2. 右側選 Configure Global Security

Configure Global Security

slack005

  1. 不勾選 Enable security
  2. 不勾選 CSRF Protection

因為 Jenkins 只是跑在本機,所以使用較寬鬆的 security 設定

建立 Jenkins Job

每一個自動化,在 Jenkins 稱為 Job。

slack006

  1. 若是第一次使用 Jenkins,可使用首頁的 create new jobs 建立新 job
  2. 若已經有其他 job,可使用左上角的 New Item 建立新 job

slack007

  1. 輸入 Job 名稱
  2. 選擇 Freestyle project

slack008

  1. 選擇 Build
  2. 選擇 Add build step
  3. 選擇 Execute shell

slack009

切換到 /var/code 的單元測試目錄下,使用 dotnet test 執行單元測試。

目前是在 Linux 下跑單元測試,也可彌補之前只在 macOS 跑單元測試,但 production 是 Linux 的缺憾

slack010

  1. 選擇 Build Now,第一次執行 job
  2. Jenkins 執行單元測試,得到 藍燈

設定 Git


目前為止,Jenkins Job 已經設定好,但必須手動使用 Build Now 執行 Job,我們希望的是每次 Git commit,就會自動執行 Jenkins job,不用我們操心。

新增 post-commit
post-commit

1
2
3
#!/bin/sh
curl http://localhost:8080/job/NumberSeriveUnitTest/build
echo "post commit trigger"

到專案的 .git/hooks目錄下,新增 post-commit,讓每次 Git commit 時執行 Jenkins job。

Jenkins 的網址規則為 /job/[Job名稱]/build

最後記得使用 chmod +x post-commitpost-commit 有執行權限。

建立新 Commit

slack011

  1. false 改成 true
  2. 新增 commit

slack012

Jenkins 自動執行單元測試,得到 紅燈

這個 紅燈 是我們預期的,因為由 false 改成 true,單元測試一定會失敗

設定 Slack


目前為止,每次 Git commit 都會自動執行 Jenkins 單元測試,唯每次都必須回到 Jenkins 才知道單元測試是否成功,若能將結果推送到 Slack,我們就能把 Slack 當成持續整合的訊息平台。

新增 Channel

slack013

  1. 按下 Channels 右側的 + 新增 channel

slack014

  1. Privacy : 設定為 PublicPrivate channel
  2. Name : 設定 channel 名稱
  3. Purpose : channel 的功能描述,可以不輸入
  4. Send invites to : 設定 channel 成員,可以稍後再設定
  5. Create Channel 開始建立 channel

slack015

  1. Got It! 進入 channel

slack016

  1. 正式進入 channel,將來 Jenkins 訊息會傳進此 channel

新增 Notification

slack017

  1. 選擇右上方的 option
  2. 選擇 Add an app

新增 Jenkins App

slack018

Slack 將開啟瀏覽器

  1. 稍微往下捲輸入 Jenkins
  2. 選擇 Jenkins CI

新增 Configuration

slack019

  1. Add Configuration 加入 Jenkins CI

新增 Integration

slack020

  1. Add Bitbucket Integration 正式加入整合 Jenkins

Slack 設定完成

slack021

  1. 介紹 Jenkins 設定流程

Slack 部分已經設定完成,接下來是 Jenkins 的設定

Slack 網頁先不要關閉,稍後會用到

設定 Jenkins


Manage Jenkins

slack022

  1. 左側選擇 Manage Jenkins
  2. 右側選擇 Manage Plugins

安裝 Slack Plugin

slack023

  1. 選擇 Avaliable tab
  2. 選擇 Slack Notification Plugin
  3. Download now and Install after restart

新增 Webhook

slack024

  1. 左側選擇 Manage Jenkins
  2. 右側選擇 Configure System

slack025

Global Slack Notifier Settings 下設定

  1. Base URL : 貼一段 Slack 所提供的 URL
  2. Integration Token : 貼一段 Slack 所提供的 token

Q : 要貼什麼 Base URL 與 token 呢 ?

slack026

回到 Slack 最後的網頁往下捲到 Step 3

  1. Base URLIntegration Token 複製貼上

最後按 Save 存檔。

設定 Job

slack027

  1. 選擇要發 Slack 通知的 job
  2. Configure 設定

slack028

在 Jenkins 執行完 build 動作後,無論成功或失敗,將結果通知 Slack

  1. 選擇 Post-build Actions
  2. 選擇 Add post-build action
  3. 選擇 Slack Notification

slack029

選擇希望 Jenkins 通知 Slack 的動作 :

  1. 選擇 Notify FailureNotify SuccessNotify Unstable

建議不用選擇太多 action,success 確認 Jenkins 還活著,FailureUnstable 確認 CI 失敗即可

slack030

新增一個 Git commit,就可發現 Slack 收到 Jenkins 測試成功 綠燈 的訊息。

Conclusion


  • 實務上若 Git repository 放在 GitHub 或 Bitbucket,則可將 Jenkins 放到雲端主機的 VM 上,大致上的流程與設定與本文類似
  • 本文雖然只針對單元測試示範,但也適用於整合測試與驗收測試
  • 將較耗時的整合測試與驗收測試交給 Jenkins 處理,在開發時只要針對單元測試即可,若 Slack 出現紅燈,再回來關注整合測試與驗收測試失敗的部分