[實作筆記] 一些關於 Azure Resource Group 的冷知識

前情提要

Resource Group 是 Azure 上比較特別的一個設計,
這裡拿來記錄一些知道就知道,不知道就不知道的小事務。

本文

NetworkWatcherRG

注意

當您使用 Azure 入口網站 建立網路監看員實例時:

網路監看員實例的名稱會自動設定為NetworkWatcher_region,其中region會對應至 網路監看員 實例的 Azure 區域。
例如,在美國東部區域中啟用的網路監看員名為NetworkWatcher_eastus。
網路監看員實例會建立在名為NetworkWatcherRG的資源群組中。 若尚無該資源群組,將會加以建立。

Azure DevOps

當我們將 Azure DevOps 的 Billing 綁定之時,
會建立一組 VisualStudioOnline-XXXX 的 Resource Group

(fin)

[實作筆記] Macbook 壓縮檔案

前情提要

假設分享機密文件給同事或者發送文件到郵件或雲端儲存時,就必須手動處理壓縮和加密,
可以參考一些文章,大致有三個作法

  • 購買付款壓縮軟體
  • 使用雲端服務
  • 手動執行 terminal 指令

手動執行就可以處理的問題,我不會特別想要付款買一個軟體,
而雲端服務會擔心資訊安全,特別是要加密的資料代表有一定程度的重要性。
Terminal 大概是網路文章的主流解。
當我需要經常這樣做時,就太麻煩了,還要記得操作指令,額外增加心智負擔。
理想上,我希望只要選擇文件或資料夾,右鍵點擊”Zip with Password”,就能創建加密的 zip 文件。

實作

  1. 打開 Automator app。

  2. 創建一個新 Automator 文件:File > New (或按 ⌘N),選擇 “Quick Action” 類型。

  3. 將輸入類型更改為 “files or folders”。

  4. 在左側的 Actions library 中,雙擊 “Run AppleScript”,或拖放到右側工作區。刪除示例代碼,替換為第 5 步的腳本。

  5. 複製並粘貼下面的 AppleScript 代碼。

    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

    set prompt_text to "請輸入壓縮密碼"

    repeat
    set zip_password to text returned of (display dialog prompt_text default answer "" with hidden answer)
    set verify_password to text returned of (display dialog "再次輸入壓縮密碼" buttons {"OK"} default button 1 default answer "" with hidden answer)
    considering case and diacriticals
    if (zip_password = verify_password) then
    exit repeat
    else
    set prompt_text to "密碼不一致,請重新設定"
    end if
    end considering
    end repeat

    tell application "Finder"
    set the_items to selection
    if ((class of the_items is list) and (count of the_items) > 0) then
    set items_to_zip to ""
    repeat with each_item in the_items
    set each_item_alias to each_item as alias
    set item_name to name of each_item_alias
    set item_name to quoted form of (item_name & "")
    set items_to_zip to items_to_zip & item_name & " "
    end repeat

    set first_item to (item 1 of the_items) as alias
    set containing_folder to POSIX path of (container of first_item as alias)
    set zip_name to text returned of (display dialog "輸入壓檔名" default answer "")
    set zip_file_name to quoted form of (zip_name & ".zip")

    if zip_password is not equal to "" then
    -- 如果存在密碼,執行加密壓縮
    do shell script "cd '" & containing_folder & "'; zip -x .DS_Store -r0 -P '" & zip_password & "' " & zip_file_name & " " & items_to_zip
    else
    -- 否則執行單純壓縮
    do shell script "cd '" & containing_folder & "'; zip -x .DS_Store -r0 " & zip_file_name & " " & items_to_zip
    end if
    else
    display dialog "你未選擇任何檔案。" buttons {"OK"} default button 1
    end if
    end tell

  6. 儲存工作流程:File > Save (或按 ⌘S),給它一個名字,如 “Zip with Password”

現在,選擇文件或文件夾,右擊,選擇 “Quick Actions” 中的 “Zip with Password”,
按照提示輸入密碼、驗證密碼和設置 zip 文件的名字。測試新創建的 zip 文件,確保一切運作正常。

參考

(fin)

[實作筆記] ClamAV 安裝

提要

因 ISO 需要在 GCP VM(Linux 系統)上安裝防毒。
ClamAV 是一款強大的開源防毒引擎,專為檢測和清除惡意程式而設計。
這篇用來記錄終端機中安裝和配置 ClamAV,包括系統更新、病毒庫更新、自動運行設定等步驟,
以確保系統有效抵禦各種威脅。

實作

首先,在終端機中輸入以下指令,展開系統更新的步驟:

1
sudo apt update && sudo apt upgrade

出現警示請按 Y

1
2
After this operation, 12.1 MB of additional disk space will be used.
Do you want to continue? [Y/n] Y

接著,透過以下指令安裝 ClamAV,一強大的防護工具,以確保系統免受惡意程式的侵害:

1
sudo apt install clamav clamav-daemon -y 

當安裝完成後

確保沒有其他 freshclam 進程在運行,您可以使用以下指令查看:

1
ps aux | grep freshclam

如果有其他 freshclam 進程在運行,請終止(kill)它們。

執行以下指令可更新 ClamAV 的病毒定義庫:

1
sudo freshclam

隨後,您可以進行系統掃描,以查找並清除潛在的威脅,請使用以下指令:

1
sudo clamscan -r /path/to/folder

若欲使 ClamAV 在系統啟動時自動運行,請執行以下指令:

1
sudo systemctl enable clamav-daemon

這將設定 ClamAV 在每次系統啟動時主動保護您的系統。

啟動 ClamAV 服務(如果它沒有在系統啟動時自動啟動):

1
sudo systemctl start clamav-daemon

檢查 ClamAV 服務的運行狀態:

1
sudo systemctl status clamav-daemon

這樣,您可以確保 ClamAV 已經更新、服務已經啟動,並檢查服務的當前運行狀態。

參考

(fin)

[生活筆記] 2023 的回顧與展望

引言

2023 年過去了, 作個回顧

工作相關

2023 年對我來說是個不穩定的一年,甚至考慮出國去唸語言學校,但最終留在了台灣。
T 社的本來想說點什麼,一年內提筆多次想想就又算了。
一年都過了還是作個簡單記錄。

T 社事件

本來想加入一個前輩 S 作為主管的團隊,
與這位前輩其實沒那麼多接觸,但知道技術實力不差,本來也是 N 社早期的創業員工之一。
預計是希望能近距離合作並學習,並以創業心態開發一款國際產品。
實際上加入 T 社後,S 桑進公司的次數屈指可數,
產品的發展也與預期不符,市場已有大量類似的競品,老闆吹的天花亂墜,但只是一個點餐系統
T 社本身到母公司 W 集團,完全缺乏軟體專案的管理經驗,隨便而缺乏專業開發團隊,
而缺乏軟體工程的管理專業,使得他們無法有效追蹤進度

需求與溝通

後續的結果是開發團隊與 W 集團互信不足,演員底的老闆,只能帶著兒子、特助或是咖啡甜點來信心喊話,
團隊內的產品部門變成了對講機與美工,唯一的功能就是轉達集團的需求與繪製 Figma。
整個產品團隊無法回答開發團隊的疑問,反而不斷的抱怨集團、特助或老闆,
整個溝通變得無效且變形

開發

反過來是招募時,餅畫得太大,導致 RD 明顯過度設計,
比如說,RD 跑了一個沒有 Domain Expert 的 DDD,
在沒有上線、沒有賺錢沒有用戶的情況下,用自已的腦補進行了領域的分工,
不到10人的團隊切分了 10 幾個微服務,並且濫用了 GraphQL。
這樣又帶來後續的問題,
第一、語言不一致,一開始的想法是讓各個開發者有開發的自主,但問題變成無法互相支援,各自畫地為王
第二、開發風格不一致,即使是使用相同的語言,使用的套件與寫作風格也未統一,所以要支援也有難度
第三、開發準備作業多,很多需求經討論後都需要新建成服務,RD 需要從建立 Repo,
到自行建置 GCP 相關服務(網路、資料庫、CI/CD 等),
第三、串接複雜,API 重重呼叫,為了要追蹤錯誤,需要延申很多額外的設計,
一個簡單的 CRUD,需要兩個 GraphQL 如果有要異動到呼叫的 API,更新一個 API 就要動到三個專案
第四,但是因為團隊缺乏領導者(S 桑)的情況下,開發者沒有有效的權責分工,GCP 的權限被一些早期入職的員工掌握,而需要等待。
第五,無溝通與不透明,晨會就形同虛設,整個團隊每個人變成一個一個穀倉

缺乏用戶

整個產品核心的兩個功能(點餐與收費)在兩個系統上,一個外部公司開發的軟體,一個在老舊的 POS。
而我們開發的系統比較像是一個單純的 App 加周邊整合。
這麼簡單的東西,卻用了一個複雜的架構,導致修改速度緩慢,遲遲無法上線,面對需求調整時也沒有彈性。
更進一步加深集團與開發團隊的不信任。

團隊狀況

  • 資料與雲端權限在一個菜鳥身上,不論有意無意,權限與知識不願意共享,除非有人踩到雷
  • 前端上班睡覺,開發品質低下的 React(完全沒有模組化的思維,不如用原生三本柱開發還比較快)
  • 產品設計的後台實務上沒有人會使用,主要還是在母公司的 ERP E
  • APP 組用了 Flutter 思維確停留在 IOS/Android/Web 的分工,到後來兩人也無法互相支援
  • 想學 C# 的 RD 整天吹噓 N 社的失敗專案(XmiERP),而代碼品質可讀、可測試性極差,讓我理解 Php 工程師的下限
  • 想學 Golang 的 RD 應該是整體過度設計的原兇,第一時間離職了。
  • 領頭 S 桑遲遲未進入團隊後,
  • 來了一個之前也在 N 社待過”幾天”的 R 主管
    • 缺乏開發能力(至少在這樣的穀倉下)
    • 也缺乏軟體開發管理的素養
    • 甚至連基本守法都作不到

  

勉強要說會作簡報,但是產品設計不合理,比如說,他花了 3 個月作簡報搞了一個動態標籤點餐,
然後跟廠商要了一個動態標籤機,丟在那裡再放3個月,然後拒絕承認有過這件事ಠ_ಠa,是在哈囉。
然後面試找來自已的樁腳。
整個公司與團隊缺乏互信

我的努力

試著找 S 桑與團隊開了一場大會,總算把 APP 推上架。
上架唯一可以收費的功能由我開發部署到實體店面驗收,並給了團隊與主管中實的逆耳忠言。
儘可能的 Change Your Company。
只可惜爛泥扶不上牆,石瓦塗黃泥也不成金。

以上是 T 社的故事概述,至於關於 R 與 W 集團的非法行為就另一個故事了(🍵

顧問

年初有找到很多的機會,例如在 C 社擔任顧問職,
或是接案,也算是個不錯的經驗,主要的發現如下。

  • 沒有識別專業能力的能力→如何確定軟體開發的產品如期如質?
  • 沒有正確分工的能力→大環境太偏向技能分工(ex:前後端、SRE、DBA etc…, 我認為應該更偏向需求端與實作端)
  • 沒有建立與管理流程的能力,版控流程、權限控管、需求流程

這剛好是我擅長且有經驗的,
資深的開發者的問題在停止學習,執著於自已的開發習慣,
資淺的開發太想炫技,而過度設計,兩者都需要透過管理手段去調控。

A 社相關

目前的事就先不多說,至少我開發的東西已經幫公司賺到 3000 萬以上,
遺憾的事是,幾個下屬想拉拉不起來,只好協議讓他離開,一切流程也合法合情,  
這也是我說的,有資金的人不見得有識別專業的能力,千里馬常有伯樂不常有。
其他一些甘苦還在進行式,至少比 T 社好多了,就不多談。

  • 主管技能學習中…
  • GCP 技術大躍進
  • ISO 認証學習中
  • Azure 技術學習中

生活

  • 潛水終於考到 AWO,下次想換個潛點了  
  • 跳舞方面
    • 跟知名的老師跳了一首,2023 足夠了
    • 上了幾個國際老師的課,不過還是沒有感到進步
      • Jo
      • Meti & Andante
      • Bianca and Nils (沒上課但是有跟 Bianca 跳到舞)
      • Lisa & Fabien
      • Dasha & Roman (有跟 Dasha 跳到舞)
      • Melanie & Jeremy
      • Chloe & Rico
      • Moondewti
      • Laura & Youngbo
    • 在誠品表演、嚐試一些空中動作 
    • 喜歡的樂手
      • Charlie Christian
      • YOASOBI
    • 喜歡的漫畫
      • 莽送的莉芙蓮
      • Völundio(休刊中)

     

  • 換了護照準備出國但是還不知道要去哪裡?
    • 打算再帶媽媽出國一次
    • 也想去倫敦看阿森納比賽
    • 也想再參加國外的 workshop
    • 不想變成只會希望而不行動的麵包師傅

展望

投資

Q1 總資產有望達到一個重大里程碑。下一個目標是持股資產達這個里程碑

英文

制定計劃中

工作

仍是目標全遠端/斜槓或接案

社交

毫無頭序,也應該制定計劃嗎???

健康

踢球?健身?跳舞

(fin)

[生活筆記] 修正 A 校的題目缺陷

導言

在 A 校擔任雲端助教一陣子,主要有幾個原因,
我也是資策會出身,所以我對轉職的學生可以感同身受,
我在教學的過程中,自已也會成長,很多時候可以學習到新知也得到成就感,
最後就是可以獲得額外的收入。

問題發現

這次是一個我有興趣的題目,簡單說 A 社利用 Replit 網站提供作業,
由學生進行撰寫,很聰明的整合方式,而且幾乎零成本。
而且我覺得最棒的是,他可以寫測試腳本,透過測試腳本,就可以驗收大部份的作業,加速批改的時間。

但是,這次同學的作業在執行時期,發生了異常掉入了一個無限廻圈的狀態
問題不難,是一個邊際值的問題。 應該可以加上測試保護,這是我的第一個直覺。
我去檢查了 A 校提供的標準答案,不出意外的也有相同的問題。

另外一個問題是,寫邊際值的測試案例不是基本的嗎?
查看了測試案例,竟然還真的沒有寫

問題排查

我選擇下載了 Replit 到地端開發,
在開始前先簡單描述題目,在一個限範圍內進行猜數字

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
const answer = Math.floor(Math.random() * 100) + 1
// start coding

let min = 1
let max = 100
let guess = Math.floor(Math.random() * 100) + 1
let count = 1

function getResult() {
while ( ) {
if ( ) {

} else if ( ) {

}
guess = Math.floor((max + min) / 2)
count ++
}
console.log( )
}

// 以下為測試檔,請勿更動
getResult()

module.exports = {
guess,
answer,
count,
getResult
}

這是很好的題目,可以同時使用到迴圈與判斷,也可以接觸 Math 模組。
我們來看一下測試案例,在 Replit 右下角的 Unit Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
test("", async function() {
const spy = jest.spyOn(console, 'log')
const {
guess,
answer,
count,
getResult
} = index;

getResult()
if (guess === answer) {
expect(count).toBeLessThanOrEqual(10)
}
});

測試很單純,當答案在 1~100 之間時,執行迴圈的次數不應該超過 10 次(其實 7 次內應該都猜得出來)
我們應該加上一些邊際測試。
例如 1 與 100 的案例,

1
2
3
4
5
6
7
8
9
10
11
12
13
it("Answer_is_1", async function() {
const spy = jest.spyOn(console, 'log');
const originalMathRandom = Math.random;
Math.random = jest.fn()
.mockImplementationOnce(() => 0.001)
.mockImplementation(() => originalMathRandom());
//console.log('now random is', Math.random());
const index = require('./index');
index.getResult();

// Clean up
spy.mockRestore();
});
1
2
3
4
5
6
7
8
9
10
11
12
13
it("Answer_is_100", async function() {
const spy = jest.spyOn(console, 'log');
const originalMathRandom = Math.random;
Math.random = jest.fn()
.mockImplementationOnce(() => 0.999)
.mockImplementation(() => originalMathRandom());
//console.log('now random is', Math.random());
const index = require('./index');
index.getResult();

// Clean up
spy.mockRestore();
});

這裡注意到的是我們 mock 了Math.random,因為這才會影響我們的答案。

問題後的問題

當我們在測試案例為 100 時,會限入無窮迴圈,而 JavaScript 單緒的特性將無法離開這個測試,
雖然也不會報錯…但是測試將永遠跑不完。
這驅使我再加上一個測試案例,當執行次數超過 10 次時拋出例外。
而學生使用的範本,我希望儘可能不去修改它,
這裡要對 jest 與 javascript 要有足夠的理解才可以寫的好,
所幸在這個時代,有 AI 與 google 的加持下,很快就解決了。

最後的測試程式如下

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
describe('Guessing Game', () => {
let originalMathRandom;
let spy;

beforeEach(() => {
// Save the original functions
originalMathRandom = Math.random;
spy = jest.spyOn(console, 'log').mockImplementation(() => {});
});

afterEach(() => {
// Restore the original functions
Math.random = originalMathRandom;
spy.mockRestore();
jest.resetModules()
});

it("Answer_is_1", async function() {
Math.random = jest.fn().mockReturnValue(0.001);
const index = require('./index');
index.getResult();
expect(index.answer).toBe(1);
});

it("Answer_is_100", async function() {
Math.random = jest.fn().mockReturnValue(0.999);
const index = require('./index');
index.getResult();
expect(index.answer).toBe(100);
});

it('guess under 10 times', () => {
Math.random = jest.fn().mockReturnValue(0.5);
const index = require('./index');
for(let i=0; i<9; i++) {
index.getResult();
}
expect(() => index.getResult()).not.toThrow();
});

it('should throw error if count is more than 10', () => {
const originalMathFloor = Math.floor;
Math.floor = jest.spyOn(global.Math, 'floor')
.mockImplementationOnce(() => Math.floor(Math.random() * 100) + 1)
.mockImplementationOnce(() => 1000);
const index = require('./index');
expect(() => index.getResult()).toThrow('超過10次了,請重新開始');

});


// Add more tests as needed for the getResult function
});

給學生的出題程式

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
const answer = Math.floor(Math.random() * 100) + 1;

// start coding

let min = 1;
let max = 100;
let guess = Math.floor(Math.random() * 100) + 1;
let count = 1;

function getResult() {
console.log(`Guess number is ${guess}`);
while ( ) {
if ( ) {

} else if () {

}

count++;
if (count > 10) {
throw new Error('超過10次了,請重新開始');
}
}
console.log(`第${count}回合,您猜${guess},猜對了`);
}

// 以下為測試檔,請勿更動
module.exports = {
guess,
answer,
count,
getResult,
};

解答範本

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
const answer = Math.floor(Math.random() * 100) + 1;

// start coding

let min = 1;
let max = 100;
let guess = Math.floor(Math.random() * 100) + 1;
let count = 1;

function getResult() {
console.log(`Guess number is ${guess}`);
while (guess !== answer) {
if (answer < guess) {
max = guess; //猜太大取代最大值
console.log(`第${count}回合,您猜${guess},太大了,請猜介於${min}~${max}之間的數字`);
} else if (answer > guess) {
min = guess; //猜太小取代最小值
console.log(`第${count}回合,您猜${guess},太小了,請猜介於${min}~${max}之間的數字`);
}
guess = (max === min + 1) ? max : Math.floor((max + min) / 2);

count++;
if (count > 10) {
throw new Error('超過10次了,請重新開始');
}
}
console.log(`第${count}回合,您猜${guess},猜對了`);
}

// 以下為測試檔,請勿更動
module.exports = {
guess,
answer,
count,
getResult,
};

小結

整個課程的調整與測試改寫,大概花了我 4~12 小時處理。
在改制後,互動環節變少了,計時制改為定時制的給薪,也讓無法花太多的時間幫學生排查問題。
這題目我有興趣就順手解決了。
可惜的是,我拿不到任何費用。

也再一次印証 AI 的強大,未來的人材需要有更高的整合能力,
寫測試寫程式,讀技術文章賺取資訊落的錢應該會越來越難賺。
但是能高度整合的人應該會更為搶手。

(fin)

[實作筆記] GCP Armor 設定

前情提要

在加入負載平衡(load balancer)後,我們發現防火牆的某些規則失效了,
尤其是那些僅允許公司內網存取站台的規則。
這是相當重要的規則,因為我們的部分開發資訊與半成品儲存在這些機器上。

之所以建立了負載平衡(load balancer),有兩個原因
首先,我需要作後端 API 的版本切換,而因為使用的程式語言不同並部署在不同主機,
而 load balancer 透過路由規則將流量導向不同的機器群的機制非常適合。
第二,我們的正式環境一直有 load balancer,而測試環境沒有,趁這個機會將沙盒/測試環境的配置調整成一致。

問題

本來有設定某些防火牆的規則,在掛載 load balancer 後就失效了。
原因是規則會識別流量的 IP,而掛載後,所有的流量對於機器來說,所有流量都來自 load balancer 的 IP 了。
這樣的規則形同虛設,這個時候 Google Armor 就是一個不錯的替代方案

Google Armor Tips

設定上十分簡單,在 Cloud Armor 頁面上選擇 policies,
我的情況是在建立 load balancer 後,就已經自動建立,
所以就直接修改。

參考規則如下

Action Type IP Addresses/Ranges Priority
Allow IP addresses/ranges 5*.1**.***.205/32 999
10.140.0.0/20
Deny IP addresses/ranges 0.0.0.0/0 1,000
(block all)

一個是對指定來源 IP 與內網允許流量進來,一個是拒絕所有流量,這裡的設定與防火牆蠻像的。
接下來是目標的部份,要設定你的機器群,設定好套用,大約 10 分鐘內就會生效(實測不到3分鐘就生效了)

小結

Google Armor的主要優勢之一是其簡單易用的設定。
在Cloud Armor頁面上,我們可以輕鬆地設定我們的安全策略,包括允許特定IP範圍的流量進入,同時拒絕不受歡迎的流量。
這些設定反映在我們的參考規則中,確保了對特定IP和內部網路的控制,同時阻止不受歡迎的流量。

特別是對於我們使用負載平衡器進行後端API版本切換和環境配置調整的需求,Google Armor提供了一個理想的解決方案。
其能夠在不同機器群之間巧妙地分發流量,確保我們的應用程式在不同版本之間平穩運作,同時維持良好的安全性。

這樣的調整不僅解決了我們遇到的具體問題,也提升了整體系統的安全性和可靠性。

(fin)

[實作筆記] Hexo 7 升級的錯誤處理心得

前情提要

最近在對Hexo進行升級至7.0版本的過程中,遇到了一些錯誤與問題。
這篇部落格將記錄下這次升級的過程中所遇到的問題以及解決方法,希望對有需要的讀者有所幫助。

錯誤記錄

Hexo Action 錯誤

升級後,遇到了Hexo Action報錯的問題,錯誤訊息如下:

1
2
3
4
5
6
node:internal/modules/cjs/loader:1051
throw err;
^

Error: Cannot find module 'hexo-util/lib/spawn'
Require stack:

解決方式是查找相應的模組,更新配置文件,在本案中,hexo-util/lib/spawn 路徑不存在,應該改為 hexo-util/dist/spawn。

地端執行 Hexo d 時 Permission Denied

在地端執行Hexo d時,遇到了權限問題,無法提交到GitHub的問題。
暫時解決方式是將repository的協議由ssh改為https,暫時繞過了問題。

1
2
3
4
deploy:
type: git
repository: https://github.com/marsen/marsen.github.io.git
branch: master

後來因 https 需要提供帳號密碼,而這些資訊不適合簽入版本控制,故改回了 ssh,
為了解決相應的 SSH 連線問題,需配置 SSH 連線 .ssh/config
參考:

1
2
3
4
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa

YouTube Tag 無法處理

升級至Hexo 7.0後,發現內建的YouTube標籤無法使用,原因是Hexo 7.0中刪除了這些內建的標籤。
解決方式是引入安裝 hexo-tag-embed package。

Hexo 部署錯誤快取

在部署過程中,遇到了Hexo的快取問題,導致地端和CI都出現異常。
解決方式是清除 Hexo 的快取 hexo clean,完整 SOP 如下:

1
2
3
4
sudo rm -rf .deploy_git
hexo clean
hexo g
hexo d

使用 Docker 偵錯

Hexo Action本身是以容器去運行的,可以在本地端執行測試,不需推版
使用 Docker 進行 Hexo Action 時,進行偵錯的方法:

建置與執行

1
2
docker build -t hexo-action .
docker run -d hexo-action

觀察 logs 與 files 去偵錯,Docker Desktop 是很好的工具。

小結

這次Hexo 7.0的升級過程中,遇到了不少問題,但通過查找相應的解決方案,一一解決了這些問題。
在升級過程中,需要留意Hexo的官方文檔以及相關插件的更新,以確保能夠順利完成升級。

參考

(fin)

[實作筆記] Gitlab CI/CD 與 GCP - 錯誤處理

前情提要

在持續整合/持續交付 (CI/CD) 的過程中,我們常常會遇到一個問題:
當發生錯誤時,系統並不總是會拋出 exit 1 的錯誤碼。
這種情況下,即使發生錯誤,CI/CD 仍然會繼續執行,這可能導致部署了錯誤的版本上線,增加系統的不穩定性。

解決方法

為了解決這個問題,我們可以採取一些措施,確保在發生錯誤時 CI/CD 立即停止,並拋出 exit 1 錯誤碼。

1. 記錄錯誤信息到 output.log

首先,我們可以將所有的執行日誌輸出到一個文件,例如 output.log。這樣一來,
不管是哪個階段出現了問題,我們都能夠查閱這個文件,以便更好地理解錯誤的發生原因。

1
2
3
Copy code
# 在腳本中添加以下命令,將所有輸出寫入 output.log 文件
./your_script.sh > output.log 2>&1

2. 使用 grep 檢查錯誤

其次,我們可以使用 grep 命令來檢查 output.log 文件,查找關鍵字或錯誤模式。
如果發現了任何錯誤,我們可以採取相應的措施。

1
2
3
4
5
6
Copy code
# 使用 grep 查找關鍵字,並在發現錯誤時執行相應的操作
if grep -q "error" output.log; then
echo "Error found in output.log"
exit 1
fi

3. 發現錯誤時丟出 exit 1

最後,在檢查完錯誤後,如果發現了問題,我們應該明確地拋出 exit 1,這會通知 CI/CD 停止進一步的運行,
確保不會將有問題的版本部署上線。

1
2
3
4
5
6
Copy code
# 在發現錯誤時,明確地拋出 exit 1
if [ $? -ne 0 ]; then
echo "Error occurred. Exiting with code 1."
exit 1
fi

透過這些步驟,我們可以更好地管理 CI/CD 中的錯誤,確保系統的穩定性和可靠性。
同時,我們能夠更快速地響應和解決問題,減少部署錯誤版本的風險。

1
2
3
4
5
6
7
8
9
10
11
12
generate-qa:
stage: generate-qa
script:
- npm install
- npm run generate:qa | tee output.log # 可能出錯的命令,將輸出寫到文件
- grep -q "Error.*\[500\]" output.log && echo -e "\e[31m生成異常! Prerendering 發生 500 Error\e[0m" && exit 1
- echo "generated successfully"
artifacts:
paths:
- ./.output/public
rules:
- if: '$CI_COMMIT_BRANCH == "qa"'

小結

這些方法不僅有助於提高系統的穩定性和可靠性,還能夠加速問題的識別和解決過程,減少了部署錯誤版本的風險。
透過這些實踐,我們可以更加信心滿滿地運用 Gitlab CI/CD 與 GCP,確保順暢的開發和部署流程。

參考

(fin)

[工作筆記] 退出 Azure DevOps 的組織

前情提要

Azure DevOps 是一個由微軟開發的服務,提供開發團隊協作和快速交付軟體的解決方案。
它包含了版控、工作追蹤、持續整合/持續部署 (CI/CD) 等功能。
其中,我將重點使用其 Board 功能來進行工作項目的管理和追蹤。
然而,有一天我發現自己被不知名的人邀請進了一個 Azure DevOps 的 Organizations,
所以我開始尋找如何自行退出的方法。

解法

首先進入 dev.azure.com,點擊 user setting icon (這在畫面的右上角,是一個人的右下角有齒輪的圖案)。
點擊 Profile 進到以下頁面,可以看到提示如下:

1
2
You are currently subscribed to other communication regarding Visual Studio and/or Visual Studio Subscriptions.   
Please visit the complete Azure DevOps Profile Page to change those settings.

點擊連結到 Azure DevOps Profile Page

這裡就可以看到你的 Organization 並選擇離開

誤區

my account 也有 Organization 但是不可以隨意離開。
簡單來說,在微軟的 my account 中,Organizations 代表的是你所屬於的 Azure Active Directory (Azure AD) 組織。
這些組織可能是你的工作場所、學校或其他團體,他們使用 Azure AD 來管理員工或成員的身份和訪問權限。
這裡的組織並不等同於 Azure DevOps 中的 Organizations,並且不能隨意離開。

參考

(fin)

[踩雷筆記] 解決 GitHub 帳戶在 VS Code 中的管理問題

前情提要

當我使用 VS Code 時,我需要同時存取多個 GitHub 帳戶,
自已的 Github - 主要存取 VS Code 一些地端的設定值
公司的 Github - 有免費的 Copilot 這很好用。
兩個都我需要,我要作出大人的選擇。

實務上的困境

我可以同時登入兩組帳戶,但是無法達到我要的需求

登入兩組帳戶的方法

  1. 確保安裝了 Github Copilot 與 Github Pull Request and Issues 套件
  2. 如果有其它 Github 帳號已經在登入狀態的,都先登出,並重啟 VS Code
  3. 準備好兩個瀏覽器,分別登入公司與自已的 Github Account
  4. 點擊在左下的頭像 Icon (沒有頭像 Icon 的話在左側欄任一處點右鍵,將帳戶打勾)
  5. 選擇”使用 Github 登入,以使用 Github Copilot”
  6. 選擇登入公司帳戶的瀏覽器,此時會提示要開啟 VS Code,選擇開啟
  7. 回到 VS Code,重複第 4 步
  8. 選擇”使用 Github 登入,以使用 Github 提取要求和問題”
  9. 選擇登入自已帳戶的瀏覽器,此時會提示要開啟 VS Code,選擇開啟

如果你的預設瀏覽器是登入公司 Github 的帳號,就複製網址,貼到登入自已的 Github 帳號瀏覽器,反之亦然。
但是這個作法,實際上沒有什麼幫助,備份與同步設定與 Copilot 會共用同一組帳號
我並不需要 Github Pull Request and Issues 相關功能。

手動組態同步

早期 VSCode 有人寫了組態同步的擴充套件,但是目前內建在 VSCode 內部後不再維護了。
但是我需要的就是自已長期以來的使用的設定,所以可以先登入自已的帳號。
再登出後,登入公司帳號。缺點是需要手動處理。

安裝第二個 VSCode

這個方法也有很多不同的實作方式。
簡單說一個官方直接支援的方式。 VS Code Insider
這算是一個搶先試用版的 VSCode,也有其對應的風險。
但是你就可以在系統上安裝兩個 VSCode,並登入不同的帳戶。

花錢為自已的帳戶買 Copilot

這或許才是最大人的解法。
我們要的是”同步組態設定”與”Copilot”使用權。
根帳號本身其實沒有什麼關係。
資本主義大好,但就失去了一些童趣了。

參考

-https://tutorials.tinkink.net/zh-hant/vscode/copilot-usage-and-shortcut.html
-https://code.visualstudio.com/docs/?dv=osx&build=insiders

(fin)

Please enable JavaScript to view the LikeCoin. :P