CI/CD 環境建置筆記(二) - 在 windows 安裝 Jenkins 之旁門左道私有雲

應該要知道的事

問題

在 windows 上安裝了 Jenkins , 也建立了一個新的作業 ,
讓程式可以透過 Jenkins 執行自動化部署。
不過實務上仍有缺點,那就是只有這台機器可以執行部署 ,
最理想的狀況是擁有一個在雲端的 CI Server ,
隨時隨地想部署只需要能連上網 , 登入執行就好
這部份可以試試看 Travis-CICircleCI之類的服務 ;
不過對於只熟悉 Jenkins 的我來說 ,
我想了另一套解決辦法(旁門左道) ,
不過至少解決了我目前的需求 ,
在公司與家中隨時都能透過本機 Jenkins Server 進行部署 ,
並且不用花時間同步設定值.
在花時間研究Travis-CICircleCI的部署方式之前 ,
算是一個折衷的方式 .

方案

  1. 首先你要有 Dropbox
  2. 下載 Windows 版的 Jenkins
  3. 安裝在 Dropbox 資料夾內
  4. 在另外一台電腦 , 進行相同的安裝

想法很簡單 , 透過 Dropbox 與 Jenkins Service
在兩台電腦安裝 Jenkins
只要將 Jenkins Service 的啟動路徑
設定在 Dropbox 中 ,
就可以達成我們的目標 .

問題

  1. Windows 要如何修改 Jenkins Service 的啟動路徑 ?

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Jenkins

修改路徑以符合你本機的檔案位置即可。

(fin)

[活動筆記] 單元測試這樣玩就對了

應該知道的事

案例一、數值區間

1
2
3
4
5
6
假定給任一整數區間
ex:
(1,6] = {2,3,4,5,6}
[-2,4) = {-2,-1,0,1,2,3}
透過一個function(x)檢查x是否包含在整數區間內,
並撰寫測試,驗証 function(x)是對的。

解析

如上範例所示,
「(」「)」小括號(parentheses)表示OPEN(不包含,大於或小於)
「[」「]」中括號(square brackets)表示CLOSE(包含,大於等於或小於等於)
(1,6] , 代表這個區間大於 1 小於等於 6,包含的整數有 2、3、4、5、6
[-2,4), 代表這個區間大於等於-2 小於 4,包含的整數有-2、-1、0、1、2、3

解析

這題比較單純,只需要考慮所有的情況,
並且寫成單元測試即可。

  1. x 落在區間內
  2. x 落在左邊界外
  3. x 落在右邊界外
  4. x 落在左邊界上,左邊界為OPEN
  5. x 落在左邊界上,左邊界為CLOSE
  6. x 落在右邊界上,右邊界為OPEN
  7. x 落在右邊界上,右邊界為CLOSE

有幾種特殊的情境,特別說明一下

  1. 假設區間為(0,1),這個區間是不包含任何整數
  2. 假設區間為(1,1),這個區間是不包含任何整數,且不包含任何數值
  3. 假設區間為[1,1],這個區間恰巧包含 1 個整數,且只包含 1 這個整數
  4. 假設”區間”為[2,1],或任何左邊界大右邊界的表示,這不是一個正確的區間,將要作例外處理。

讓我們回歸單元測試,
這裡的重點是一個測試只作一件事,
只把一個情境釐清,並且在測試的程式碼中
明確的表達測試目的

1
2
3
4
5
6
7
8
9
10
11
12
private int leftBound = 1;
private int rightBound = 6;
private int testNum = 4;

[TestMethod]
public void IncludeWhenLeftOpenRightClose()
{
var checker = new RangeChecker(Bound.Open,this.leftBound,Bound.Close,this.rightBound);
bool expect = false;
bool result = checker.IsContains(testNum);
Assert.IsTrue(result);
}

案例二、現在時間轉字串

1
2
3
寫一個方法GetNowString,不傳入任何參數,
取得現在的時間字串,需要精準到豪秒。
再寫一個測試去測試這個方法是對的‧

版本 1

最簡單的寫法:

1
2
3
4
5
6
7
public class DateHelper
{
public string GetNowString()
{
return DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss ff");
}
}

撰寫測試

1
2
3
4
5
6
7
8
9
[TestMethod]
public void GetNowString()
{
var
//// 寫不下去,因為我們無法凍結系統的時間
string expect = "2017-04-19 20:45:17.88";
string result = dater.GetNowString();
Assert.AreEqual(expect, result);
}

解析 1

GetNowString與系統的時間DateTime.Now,
是具有耦合性,要解耦需要透過一些 IoC 的手段去處理。

版本 2

利用繼承的方法,作出假的類別

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class DateHelper
{
protected DateTime now;
protected virtual DateTime GetNow()
{
now = DateTime.Now;
return now;
}

public string GetNowString()
{
GetNow();
return now.ToString("yyyy-MM-dd HH:mm:ss.ff");
}
}

class StubDateHelper: DateHelper
{
protected override DateTime GetNow()
{
return now;
}

public void SetNow(DateTime datetime)
{
now = datetime;
}
}

撰寫測試

1
2
3
4
5
6
7
8
9
10
[TestMethod]
public void GetNowString()
{
StubDateHelper dateHelper = new StubDateHelper();
var fakeNow = new DateTime(2017,4,19,20,45,17,880);
dateHelper.SetNow(fakeNow);
string expect = "2017-04-19 20:45:17.88";
string result = dateHelper.GetNowString();
Assert.AreEqual(expect, result);
}

解析 2

基本上這樣就可以測試了,
原來的代碼,經過一定的重構,
透過virtual方法 GetNow,
Datetime.Now作了隔離
適當利用假類別,取代掉 GetNow 的方法。

這樣夠好了,但是我們可以看看另一種作法

版本 3

先看看我們的DateHelper,
在這裡我們將 GetNow 交由 IDateProvider 的類別去實作,
如此一來就斷開了耦合性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DateHelper
{
private IDateProvider DateProvider;

public DateHelper(IDateProvider dateProvider)
{
this.DateProvider = dateProvider;
}

public string GetNowString()
{
var now = this.DateProvider.GetNow();
return now.ToString("yyyy-MM-dd HH:mm:ss.ff");
}
}

實作 IDateProvider 的類別,
在這裡其實不重要.

1
2
3
4
5
6
7
public class DateProviderV1 : IDateProvider
{
public DateTime GetNow()
{
return DateTime.Now;
}
}

讓我們看看測試,
在這裡我們透過一個假的IDateProvider的實作DateProviderStub,
完成了測試,
IDateProvider 將DateTime.Now作了隔離,
並且提供更容易修改的假物件(僅僅需要實作觀注的方法即可,不用擔心繼承帶來的附作用)

1
2
3
4
5
6
7
8
9
10
[TestMethod]
public void GetNowString()
{
DateProviderStub dateProvider = new DateProviderStub();
dateProvider.now = new DateTime(2017, 4, 19, 20, 45, 17, 880);
var dateHelper = new DateHelper(dateProvider);
string expect = "2017-04-19 20:45:17.88";
string result = dateHelper.GetNowString();
Assert.AreEqual(expect, result);
}
1
2
3
4
5
6
7
8
public class DateProviderStub : IDateProvider
{
public DateTime now;
public DateTime GetNow()
{
return now;
}
}

圖例解析

我們剛剛究竟幹了什麼?
我們剛剛究竟幹了什麼?
看看原本的情況,本來的方法因為相依與Datetime而無法測試
相依Datetime
讓我們開始下刀,
先用一個新的方法GetNow
將它與待測的方法作分割,
但是對整個類來說仍舊是耦合。
耦合
繼續把這刀往下切,
我們墊一層介面,
待測方法不再直接呼叫GetNow
而是透過介面執行,當然會有額外實作介面與注入的功(請參考程式碼,不在此處繪出了.)
透過介面執行
最後,別忘了我們的目的
測試原本的待測方法,
我們可以透過一個假的類,
來操控他的行為(ex:凍結時間).
如此一來,就可進行測試了.
測試
另外,這種被待測方法呼叫後
會回傳一個假值的方法或類
被叫作STUB
STUB

案例三、發送郵件

事先聲明,這題沒有程式碼,
有興趣實作的人可以試試看.
如果可以分享實作後的資訊給我更好 XD

Q:註冊發送郵件如何寫單元測試?

解析
很明顯的發送郵件需要依賴外部的郵件系統,
這裡就會有耦合性,我們可以參考案例 2 的方式解耦
不過發送郵件並不會有回傳值,
我們要如何驗証正確性呢?

A:檢查調用次數、參數

圖例解析
在案例 2 的單元測試,
我們透過 STUB 偽造的回傳值完成測試
並執行驗証.
但是在沒有回傳的值的方法中(被稱作MOCK)
我們只能透過傳遞的參數(如果有多載)
與方法被調用的次數來進行驗証。

MOCK

重點摘要

  • 單元測試要能清楚表達測試的目的(達意)
    • 命名
    • 減少意外的細節
  • 單元測試一次只作一件事
  • new 本身就是一種邏輯 一種偶合
  • static 是一種高偶合
  • 繼承也是高偶合,能使用繼承的情境很少
    • A is a B 通常只有這種情境才適合繼承
  • STUB & MOCK
    • STUB 會有回傳值,可以在 Unit Test 作驗証(ASSERT)
    • MOCK 沒有回傳值,可以在 MOCK 本身中 作驗証(ASSERT)

其它

  • SLIM
  • 注入相依的幾種方式
    • Pool
    • Constructor
    • Property
  • 書單 : XUnit Test Patterns

直播影片

如果連結失效,煩請告知.

文章內容如有謬誤,煩請指正.

(fin)

[閱讀筆記] 其實,你不是沒有時間

六個工具與餐盤

  • 原則:工具簡單至上
  • 面對突發狀況
  1. 月計劃表 (google calendar)
    • 與自已約會(保留給自已的時間)^註 1^
    • 工作與私人不要分開
    • 日期與期限
  2. Todo List (inbox)
    • 提醒與集中管理
    • 每天都要檢查一遍^註 2^
  3. 日計劃表 (google calendar)
    • 當日約會 & 活動清單
    • 活動清單是你當天的籌碼 也是出現突發
  4. 隨手記 (筆記本&Evernote)
    • 接受任務,再轉到其他工具之中^註 3^
  5. 隨身資料庫 (google drive)
    • 將整理過的資料封存在隨手可得的地方
      ex: 上課或分享的簡報、 專案記錄等…有大量圖片、文件等
  6. 溝通工具 (line & slack)
    • 一天檢查電子郵件 3~6 次就夠了

把時間變空間(視覺化)

  • 個人、家庭、工作取得平衡
  • 安排 30 分鐘規劃一天的活動
    • 創造性活動安排在精力最佳的時段
    • 安排獨處的時間
    • 安排恢復精力的時間
    • 預留時間給可能發生的突發事件
  • 將所有的事情分為紅綠黃(灰)^註 4^,綠色應該越多越好,灰色越少越好。
    6 am7 am8 am9 am10 am11 am12 am1 pm
    5 am本日活動隨手記2 pm
    4 am3 pm
    3 am4 pm
    2 am5 pm
    1 am12 am11 pm10 pm9 pm8 pm7 pm6 pm

應變執行,計劃趕不上變化

  • 調整事情的順序
  • 養成習慣
  • 臨機應變
  • 小心多工
  • 保留風格

  1. 分別為聖的時間,請參考與時間作朋友
  2. 利用分別為聖的時間檢查
  3. 餐盤中間的區塊可以用來作當日的活動清單 & 隨手記
  4. 可以參考四象限 重要-緊急(紅)、不重要-緊急(黃)、重要-不緊急(綠)、不重要-不緊急(灰)

(fin)

自動化 Trello 操作

Trello 是一個非常方便的工作管理工具,
最主要的功能只有 Boards 、 Lists 與 Cards,
確可以發揮相當大的綜效功能,
用來當作敏捷開發的白板、安排工作項目與進度,
作為協作的平台與工具。
也有相當多元的外掛可以供不同的情境使用,
開發人員也可以自行串接 API 與系統作整合。
簡單記錄自動化產生 Cards 的兩種方法。

第一種方法,使用 mail

  1. 開啟 Menu > More
  2. 點選 Email-to-board Settings
  3. 選擇你要產生卡片的 List 與 位置(頂部或底部)

  1. 寄信,信件格式如下
    • email 的 subject 會成為卡片的標題
    • email 的內容會成為卡片的描述
    • 如果有附加檔案在郵件中,會附加到卡片中
    • 在 subject 加入 #label 可以在卡片加入標籤(Labels)
    • 在 subject 加入 @member 可以在卡片加入成員(Members)

更多請參考.

第二種方法,使用 API

  1. 登入 Trello
  2. 連線 https://developers.trello.com
    點選Get your Application Key. 連線到 https://trello.com/app-key

取得 Key

生成 Token


點選 allow 後,就會顯示你的 token,特別注意登入的身份權限,
並且千萬不要外洩你的 token 與 key 值。

試打 API,建立一張 Card 到指定的 List 中.
並且設定期限(due)與標籤(labels),
更多的 API 設定請參考.

分析

  • Email:
    • 優點:簡單、方便、可以結合 mail system 、附加檔案簡單
    • 缺點:部份功能無法實現(ex: 設定 due date)
  • API:
    • 優點:靈活、Resful 的 API 可以實現大部份的功能
    • 缺點:實作比較麻煩

(fin)

ASP.NET Thread Pool 監控

前情提要

上一次說明了 .NET Thread Pool 的機制如何影響 Redis,
.NET Thread Pool 的機制會貫穿任何與它互動的系統或服務,
所以這篇會簡單描述如何對 .NET Thread Pool 建立監控

步驟

  1. 建立監控記數器
  2. 在系統寫入監控數值
  3. 開啟效能計數器

建立監控記數器

記數器 說明
Available Worker Threads 目前在 thread-pool 可以使用的 worker threads
Available IO Threads 目前在 thread-pool 可以使用的 I/O threads
Max Worker Threads 最大可以建立的 worker threads 數量
Max IO Threads 最大可以建立的 I/O threads 數量

建立一個 Console 應用程式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
using System;
using System.Diagnostics;

class MyAspNetThreadCounters
{
[STAThread]
static void Main(string[] args)
{
CreateCounters();
Console.WriteLine("MyAspNetThreadCounters performance counter category " +
"is created. [Press Enter]");
Console.ReadLine();
}

public static void CreateCounters()
{
CounterCreationDataCollection col =
new CounterCreationDataCollection();

// Create custom counter objects
CounterCreationData counter1 = new CounterCreationData();
counter1.CounterName = "Available Worker Threads";
counter1.CounterHelp = "The difference between the maximum number " +
"of thread pool worker threads and the " +
"number currently active.";
counter1.CounterType = PerformanceCounterType.NumberOfItems32;

CounterCreationData counter2 = new CounterCreationData();
counter2.CounterName = "Available IO Threads";
counter2.CounterHelp = "The difference between the maximum number of " +
"thread pool IO threads and the number "+
"currently active.";
counter2.CounterType = PerformanceCounterType.NumberOfItems32;

CounterCreationData counter3 = new CounterCreationData();
counter3.CounterName = "Max Worker Threads";
counter3.CounterHelp = "The number of requests to the thread pool "+
"that can be active concurrently. All "+
"requests above that number remain queued until " +
"thread pool worker threads become available.";
counter3.CounterType = PerformanceCounterType.NumberOfItems32;

CounterCreationData counter4 = new CounterCreationData();
counter4.CounterName = "Max IO Threads";
counter4.CounterHelp = "The number of requests to the thread pool " +
"that can be active concurrently. All "+
"requests above that number remain queued until " +
"thread pool IO threads become available.";
counter4.CounterType = PerformanceCounterType.NumberOfItems32;

// Add custom counter objects to CounterCreationDataCollection.
col.Add(counter1);
col.Add(counter2);
col.Add(counter3);
col.Add(counter4);
// delete the category if it already exists
if(PerformanceCounterCategory.Exists("MyAspNetThreadCounters"))
{
PerformanceCounterCategory.Delete("MyAspNetThreadCounters");
}
// bind the counters to the PerformanceCounterCategory
PerformanceCounterCategory category =
PerformanceCounterCategory.Create("MyAspNetThreadCounters",
"", col);
}
}

編譯後並執行即可,
執行 regedit 開啟登錄編輯程式,
輸入機碼 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
將可以找到剛剛建立的 MyAspNetThreadCounters 記數器

在系統寫入監控數值

在站台的 Global.asax 加入以下的程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public bool MonitorThreadPoolEnabled = true;

protected void Application_Start(Object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(RefreshCounters));
t.Start();
}

public void RefreshCounters()
{
while (MonitorThreadPoolEnabled)
{
ASPNETThreadInfo t = GetThreadInfo();
ShowPerfCounters(t);
System.Threading.Thread.Sleep(500);
}
}

protected void Application_End(Object sender, EventArgs e)
{
MonitorThreadPoolEnabled = false;
}

public struct ASPNETThreadInfo
{
public int MaxWorkerThreads;
public int MaxIOThreads;
public int MinFreeThreads;
public int MinLocalRequestFreeThreads;
public int AvailableWorkerThreads;
public int AvailableIOThreads;

public bool Equals(ASPNETThreadInfo other)
{
return (
MaxWorkerThreads == other.MaxWorkerThreads &&
MaxIOThreads == other.MaxIOThreads &&
MinFreeThreads == other.MinFreeThreads &&
MinLocalRequestFreeThreads == other.MinLocalRequestFreeThreads &&
AvailableWorkerThreads == other.AvailableWorkerThreads &&
AvailableIOThreads == other.AvailableIOThreads
);
}
}

public ASPNETThreadInfo GetThreadInfo()
{
// use ThreadPool to get the current status
int availableWorker, availableIO;
int maxWorker, maxIO;

ThreadPool.GetAvailableThreads( out availableWorker, out availableIO);
ThreadPool.GetMaxThreads(out maxWorker, out maxIO);

ASPNETThreadInfo threadInfo;
threadInfo.AvailableWorkerThreads = (Int16)availableWorker;
threadInfo.AvailableIOThreads = (Int16)availableIO;
threadInfo.MaxWorkerThreads = (Int16)maxWorker;
threadInfo.MaxIOThreads = (Int16)maxIO;
// hard code for now; could get this from machine.config
threadInfo.MinFreeThreads = 8;
threadInfo.MinLocalRequestFreeThreads = 4;
return threadInfo;
}

public void ShowPerfCounters(ASPNETThreadInfo t)
{

// get an instance of our Available Worker Threads counter
PerformanceCounter counter1 = new PerformanceCounter();
counter1.CategoryName = "MyAspNetThreadCounters";
counter1.CounterName = "Available Worker Threads";
counter1.ReadOnly = false;

// set the value of the counter
counter1.RawValue = t.AvailableWorkerThreads;
counter1.Close();

// repeat for other counters

PerformanceCounter counter2 = new PerformanceCounter();
counter2.CategoryName = "MyAspNetThreadCounters";
counter2.CounterName = "Available IO Threads";
counter2.ReadOnly = false;
counter2.RawValue = t.AvailableIOThreads;
counter2.Close();

PerformanceCounter counter3 = new PerformanceCounter();
counter3.CategoryName = "MyAspNetThreadCounters";
counter3.CounterName = "Max Worker Threads";
counter3.ReadOnly = false;
counter3.RawValue = t.MaxWorkerThreads;
counter3.Close();

PerformanceCounter counter4 = new PerformanceCounter();
counter4.CategoryName = "MyAspNetThreadCounters";
counter4.CounterName = "Max IO Threads";
counter4.ReadOnly = false;
counter4.RawValue = t.MaxIOThreads;
counter4.Close();
}

當你的站台重新啟動後,
就會定期將 Worker Thread 與 I/O Threads 的監控數值傳遞給系統。

開啟效能計數器

  1. 執行 perfmon.exe 開啟效能計數器
  2. 新增效能計數器(點選綠色加符號)
  3. 選取前面所建立監控記數器就能看到當前 ThreadPool 的使用狀況。
    開啟效能計數器

(fin)

IIS Tracing Log 設定

緣由

當你需要 Trace 送到 IIS 的每個 Request 的細節(包含在 pipe line 各個模組之間的 input/output 與 傳入的參數、header 等…),
可以透過開啟 tracing log 來作追蹤

環境

  1. Windows Server 2012 R2
  2. IIS 8.5.9600.16384

開啟 tracing log

  1. 新增 Tracing Rules

  2. 開啟網站 Tracing 功能

調整 IE Security 層級

  1. 使用 IE 開啟 Log,因 Security 設定無法套用版型

  2. 調整 ie enhanced security

  1. 開啟 IE > 點選小齒輪,選擇 Internet Options > 點選 Security 頁籤 > 將 Internet 的 Security Level 調整為 Medium-high

  2. 完成

(fin)

CI/CD 環境建置筆記 - 使用Openshift 的 Jenkins (失敗)

前情提要

操作記錄(失敗)

目標:

  • 在 Openshift 新增一個 Jenkins Server

失敗原因:

  • 我找不到方法在 Openshift 上建置的 Jenkins Server

記錄:

  1. 登入 OpenShift 的web console
  2. Add Application 選擇 Jenkins Server,使用預設設定 Create Application.
    Public URL 設定為 http://jenkins-youraccount.rhcloud.com
  3. 連線進 http://jenkins-youraccount.rhcloud.com 會發現需要帳密登入
  4. 取得帳號密碼
    1. 使用 SSH 連線 Openshift 的 Jenkins Server (可以在 web console 查到連結)
      > ssh 4263*****************@jenkins-youraccount.rhcloud.com
    2. 查看以下兩個檔案可以取得帳號密碼
      JENKINS_USERNAME
      JENKINS_PASSWORD
  5. 登入後,管理 Jenkins > 設定系統
    1. 將執行程式數量設定為 1
  6. 選擇新增作業
    1. 第一步要將原始碼自 Github pull 下來;在原始碼管理選擇Git , 設定好RepositoriesBranches to build
  7. 執行一次建置,這個步驟是為了產生 work space 。
  8. SSH 連線 Openshift,切換目錄到你的專案的 work space
    > ssh 4263*****************@jenkins-youraccount.rhcloud.com
    > cd app-root/data/workspace/your_project_name
  9. 檢查一下目前 Git 的遠端 Repo 有哪些
    > git remote -v
  10. 將 Openshift 上的 nodejs 應用程式 repo 設為 remote
    >git remote add openshift ssh://5**********************@nodejs-youraccount.rhcloud.com/~/git/nodejs.git/
  11. 推送到openshift remote
    失敗!!原因是權限問題,Openshift remote 是透過 SSH 連線,
    在認証公鑰的過程中,需要寫入 ~/.ssh/known_hosts 檔案。
    但是 Openshift 建立的 Jenkins Server 登入帳號,權限並不足以寫入而造成失敗

(fin)

CI/CD 環境建置筆記(一) - 在 windows 安裝 Jenkins

前情提要

操作記錄

  1. 下載並安裝 Jenkins(記錄版本為 2.32.1)

  2. 連線 localhost:8080,會要求輸入Administrator password

  3. 安裝 Plugins(這裡選擇預設)

  4. 安裝畫面

  5. 建立管理者帳號密碼

  6. 登入後,管理 Jenkins > 設定系統

    1. 將執行程式數量設定為 1 (安裝完預設為 2,其實可以不用修改)
    2. Shell 設定為 C:\Windows\system32\cmd.exe
  7. 建立第一個作業,選擇新增作業 > 輸入作業名稱 ,選擇「建立多重設定專案」

  8. 執行一次建置,這個步驟是為了產生 work space 。
    work space 路徑大致如下 .\Jenkins\workspace\Project name

  9. 執行 console 並切換路徑至 work space

  10. 將 Openshift 上的 nodejs 應用程式 repo 設為 remote
    >git remote add prod ssh://5**********************@nodejs-youraccount.rhcloud.com/~/git/nodejs.git/

  11. 回到 Jenkins,作業 > 組態 > 建置 > 新增「執行 Windows 批次指令」

    1
    2
    3
    REM 測試
    whoami
    git push prod HEAD^:master
    1. 額外處理事項:
      直接在 Jenkins server 發 pr 給 openshift 時,發生 503 錯誤。
      使用 ssh 登入 openshift 看 log ,發現
      Node Sass does not yet support your current environment 錯誤
      必須登入執行以下語法修正模組問題 npm rebuild node-sass
  12. 建置作業,會得到錯誤訊息

1
2
3
4
上略...
19:44:46 Host key verification failed.
19:44:46 fatal: Could not read from remote repository.
下略...

原因:主機密鑰驗證失敗,這個錯誤的意思是我的 Jenkins Server 主機並不認得遠端的 Openshift Server 的 host key,主要的原因是 Jenkins Service 在執行的身份是 NT AUTHORITY\SYSTEM,由於我已經有合適權限的帳號,所以只需要切換執行 Jenkins Server 的身份即可。

如果你尚未建立遠端 ssh 連線的存取權限,或是對 ssh 連線不熟悉,可以參考文末的參考聯結。

參考

(fin)

CI/CD 環境建置筆記 - 前言<目的>

現有架構

現有架構

版本控制

  1. Github
  2. Openshift

Openshift 是實際線上服務所在,也可以稱作是我的產品(Product),
Github 則是單純的負責版本控制。

開發流程

作為獨立開發的專案,這個網站只是我很單純的自我介紹、練習(KATA)、學習與分享的集散地。
原本的開發流程很單純,如上圖。完成的 CODE 同步到 GITHUB 後也同步上 Openshift ,
這樣的流程雖然簡單,但是每次都要人工執行,因為其執行順序,其實都隱含著風險,
例如:上錯版本或是產品未進版控等等…,
而當進一步想要執行建置、編譯 、套件管理、測試、分析與產生報表時,
產品與源碼將會產生差異(ex:產品會包含壓縮的檔案而源碼則是未壓縮的檔案)

缺點

  1. 在這樣的架構上容易不小心發佈還在開發中的功能。
  2. Prod 的來源就是程式碼,無法確保與版控一致,如此就喪失版控的用意。
  3. 難以擴展其他功能,如:建置、編譯 、套件管理、測試、分析與產生報表

目標

目標
如圖所示,
第一步 Jenkins 要將原始碼自 Github pull 下來
第二到第 N 步 Jenkins 要執行建置、測試、coding style 的檢查、壓縮…等等。
最後一步 Jenkins 將會將程式碼發佈到 Openshift 上面。
中間的步驟先跳過,之後再一一補上。
所以第一目標很簡單,
從 Github Pull 再 Push 到 Openshift。

(fin)

[記錄]VS2015 StyleCop 誤判SA0102

環境

  • 作業系統:Windows 10
  • 開發工具:Visual Studio 2015 (Professional ver14.0.25431.01 Update 3)
  • StyleCop 4.7.50.0

情境

當使用 C# 6 的INTERPOLATION STRING組合字串時,在 StyleCop 4.7 會誤判並回報 SA0102 的警告。

1
2
3
4
5
6
return new ExcelResult
{
Data = exportData,
FileName = $"{shopId}_Code_{DateTime.Now.ToString("yyyyMMddHHmm")}",
SheetName = "ECouponCode"
};

修正目標

  1. 將 StyleCop 4.7 更新至 StyleCop 5.0
  2. 編輯客製化的 StyleCop Rules(直接將 4.7 的設定檔覆蓋 VS 會報錯)

修正記錄

  1. 移除 StyleCop
    控制台 > 新增移除程式

  2. 移除 Visual Studio 上的 StyleCop
    工具 > 擴充功能和更新

  3. 自你的程式碼移除所有對 StyleCop 的參考
    我的程式碼中並不包含對StyleCop的參考,故略過此步驟

  4. 搜尋StyleCop*.dll 並且移除(非必要)

  5. 重新安裝 StyleCop Visual Studio Extension 1. 安裝完成檢視安裝記錄檔

    2.  可以透過安裝記錄檔取得安裝路徑
    

  6. 客製修改 StyleCop 設定檔
    5-2 的步驟可以找到Settings子資料夾,內含預設 StyleCop 設定檔,
    複制這個檔案到上一層,重新命名為Settings.StyleCop,
    透過StyleCop.SettingsEditor開啟Settings.StyleCop調整設定值。

參考

(fin)

Please enable JavaScript to view the LikeCoin. :P