Go-Live:Google Sheet to Jira 工單自動化
從雜亂的回報到結構化的 Jira 工單,實現零人工、高品質、即時通知的自動化閉環。
The Challenge
「系統上線期間問題回報量大,人工將 Google Sheet 回報轉錄為 Jira 工單不僅耗時(每張 3-5 分鐘),且常因格式不一導致溝通成本增加。」
The Solution
「開發一個 n8n 自動化工作流,定時讀取 Google Sheet,自動將回報轉換為格式標準化的 Jira 工單,並透過 Webhook 即時發送 Teams 通知,實現了從回報到指派的零人工介入閉環。」
專案緣起:Go-Live 期間的大作戰
系統上線 (Go-Live) 初期,是資訊團隊壓力最大的時刻。問題回報會從四面八方湧入:電話、LINE 群組、甚至是走廊上的攔截。為了快速記錄,大家習慣先將問題登記在一個共用的 Google Sheet,等釐清問題後,再手動建立 Jira Ticket。
但這個過程也衍生了一些後遺症:
- 大量人工: 開票時的複製貼上、欄位對應,開一張平均耗時 3-5 分鐘,一天下來就是數小時的人工作業。
- 品質不一: 不同人開的票,格式、資訊完整度參差不齊,PM 跟 RD 可能需要來回溝通才能釐清問題。
- 資訊延遲: 手動轉錄造成延遲,緊急問題可能無法在第一時間被看見,更麻煩的是,開完票還得手動貼連結到 Teams 通知大家。
身為一個懶惰卻追求效率的部分工時 QA 工程師,我覺得這樣其實不可以。因此,在專案上線的緊繃時刻,我擠出一些業餘時間,用 n8n 打造了這個自動化工作流,旨在將團隊從繁瑣的人工作業中解放出來。
🐦重點重點重點是我把這個工作流,跟之前做的 LineBot 工作流結合成 Combo 技:第一線同仁用 Line 回報並自動寫到 Google Sheets,然後再由這個工作流來自動 Create Jira Ticket,完美。 (查看 LineBot 回報機器人介紹 )
理念核心:一個聰明且自律的自動化閉環
這個 n8n 工作流的核心思想是「監控、處理、回饋、通知」,形成一個完整的自動化閉環。
- 定時監控 (Schedule Trigger): 工作流每 15 分鐘自動啟動一次,像個忠誠的哨兵,檢查 Google Sheet 中是否有新的任務。
- 智慧篩選 (Google Sheets Node): 它只抓取滿足兩個條件的資料列:
Jira Link欄位為空,且可Jira欄位被標記為 "Y"。這確保了只有經過核對確認、且尚未開票的回報才會進入流程。 - 格式化處理 (Code Node): 這是確保工單品質的關鍵。此節點會讀取所有相關欄位,將其組合成一個結構清晰、重點分明、甚至帶有彩色區塊的 Jira Wiki Markup 描述。同時,它會根據回報的「嚴重度等級」自動對應成 Jira 的 Priority ID。
- 自動開票 (Jira Node): 將格式化後的內容,連同 Assignee、Reporter、Labels 等資訊,自動建立一張高品質的 Jira Bug Ticket。
- 即時回饋 (Google Sheets Node): Jira Ticket 建立成功後,工作流會立即將含有連結的 Jira Key 回寫到 Google
Sheet 的
Jira Link欄位,並將可Jira狀態更新為 "Done",形成完美的資訊閉環。 - 主動通知 (HTTP Request to Power Automate): 最後,工作流會組合一個精美的 Teams Adaptive Card,透過呼叫 Power Automate 的 Webhook,將新工單的關鍵資訊即時推送到團隊頻道,確保重要問題不會被遺漏。
- 錯誤告警 (Telegram Node): 在流程的關鍵節點(如讀取資料、建立工單)都設置了錯誤處理,一旦發生問題,會立即發送通知到我的 Telegram,讓我能即時介入。
工作流展示
點擊下方頁籤,查看此工作流的實際運行示意:
n8n 整體工作流
從定時觸發、讀取 Google Sheet、格式化、建立 Jira Ticket、回寫狀態,到最後發送 Teams 通知,所有步驟一目了然。
輸入源:Google Sheet
維運團隊只需專注於填寫這張表單,並在確認問題後,於「可Jira」欄位填上 "Y",剩下的就交給自動化。
產出成果:結構化的 Jira Ticket
自動化流程確保每一張 Ticket 都擁有標準、清晰、帶有彩色區塊的描述,大幅提升 RD 的處理效率。
主動通知:Microsoft Teams 卡片
工單建立後,關鍵資訊會被整理成一張精美的卡片,即時發送到團隊頻道,讓所有人同步最新動態。
從 0 到 1:建立你的 Go-Live 自動化工作流
本教學將引導你完成這個 n8n 工作流的每一步。在開始之前,請確保你已經擁有 n8n 環境,並準備好 Google、Jira 和 (可選的) Telegram / Power Automate 的 API 權限。
這是工作流的起點,決定了 n8n 檢查新任務的頻率。
- 在 n8n 畫布中,新增一個 Schedule Trigger 節點。
- 將 Trigger Interval 設定為你需要的頻率,例如每 15 分鐘 (Minutes)。
這個節點會定時啟動,並將一個空的執行訊號傳遞給下一個節點。
此節點負責從 Google Sheet 中讀取需要被建立為 Jira Ticket 的回報。
- 新增一個 Google Sheets 節點。
- 在 Authentication 中選擇或建立你的 Google API 憑證。
- Resource 選擇 Row,Operation 選擇 Get。
- 填入你的 Spreadsheet ID 和 Sheet Name。
- 在 Filters 區塊設定篩選條件,這是確保不重複開票的關鍵:
- Filter 1:
Jira Link| Condition: Is Empty | Value: (留空) - Filter 2:
可Jira| Condition: Equals | Value: Y - Filter 3:
問題描述| Condition: Not Equals | Value: (留空)
- Filter 1:
- (重要) 在節點設定的 Settings 頁籤中,將 On Error 設定為 "Continue (using error output)"。這會產生一個額外的 "error" 輸出錨點,讓我們可以連接到錯誤通知節點。
如果 Google Sheet 節點因為權限、網路問題等原因執行失敗,我們希望立即收到通知。
- 新增一個 Telegram 節點。
- 設定你的 Telegram API Credentials 和 Chat ID。
- 在 Text 欄位中,填寫一個清晰的錯誤訊息,例如:「❌ GoLive Jira 自動化 - 讀取 Google Sheet 失敗!」。
- 將上一個 Google Sheets 節點的 error output (紅色圓點) 連接到此 Telegram 節點的 input。
Google Sheet 節點可能一次返回多個需要處理的列。為了確保每個回報都被獨立、穩定地處理,我們需要一個迴圈。Split in Batches 節點可以完美勝任此工作。
- 新增一個 Split in Batches 節點。
- 將 Batch Size 設定為
1。
這樣設定後,該節點會將收到的多個項目(Items)拆分成獨立的執行,一次只處理一個,直到所有項目都處理完畢。
這是提升工單品質的核心。此節點會用 JavaScript 將 Google Sheet 的原始資料轉換成結構化的 Jira Wiki Markup,並對應優先級。
- 新增一個 Code 節點。
- 將以下 JavaScript 程式碼貼入程式碼編輯區。
/**
* n8n Code Node: Format Issue Report for Jira Description (Wiki Markup) & Map Priority
*
* This script takes raw issue data and performs two tasks:
* 1. Transforms it into a structured Wiki Markup string for Jira descriptions.
* 2. Maps the text-based priority level ('嚴重度等級') to a numeric Jira Priority ID.
* If the priority level is not found or is empty, it defaults to a standard ID.
*/
// --- 1. Get data from the upstream node ---
const itemJson = $input.item.json;
// --- 2. Priority Mapping ---
const priorityMap = {
'P1': '1', // Highest
'P2': '2', // High
'P3': '3', // Medium
'P4': '4', // Low
// Default/fallback value if no match is found
'_': '3' // Default to Medium
};
// --- 3. Helper function to create a wiki markup list item ---
function createListItem(emoji, label, value, defaultValue = 'N/A') {
let displayValue = value;
if (typeof value === 'boolean') {
displayValue = value ? '是' : '否';
}
// Ensure the value is not null or undefined before displaying
return `* ${emoji} *${label}:* ${displayValue || defaultValue}`;
}
// --- 4. Build the Wiki Markup String ---
// Panel 1: Issue Report Information
const reportInfoPanel = [
'{panel:title=問題回報資訊|bgColor=#DEEBFF|borderColor=#B3D4FF}',
createListItem('💻', '系統別/地點', itemJson['系統別/地點']),
createListItem('📝', '問題簡述', itemJson['問題簡述']),
createListItem('👤', '回報者姓名', itemJson['提出者']),
createListItem('🚨', '緊急', itemJson['緊急']),
createListItem('👨⚕️', '職務', itemJson['職務']),
createListItem('📞', '聯絡方式', itemJson['聯絡方式']),
createListItem('🗂️', '病歷號/住院號', itemJson['病歷號/住院號']),
createListItem('📍', '診間或病房編號', itemJson['診間或病房編號']),
'{panel}'
].join('\n');
// Panel 2: Internal Processing Status
const internalStatusPanel = [
'{panel:title=內部處理狀態|bgColor=#FEF0B5|borderColor=#FFC400}',
createListItem('🚦', '嚴重度等級', itemJson['嚴重度等級'], '未分類'),
createListItem('🧑💻', 'Owner', itemJson['Owner(RD)'], '未指派'),
createListItem('⏳', '處理狀態', itemJson['處理狀態'], '待處理'),
createListItem('🛠️', '處理方式', itemJson['處理方式'], '分析中'),
'{panel}'
].join('\n');
// --- 5. Combine all parts and map priority ---
// Combine panels into a single description string
itemJson.jiraDescriptionString = `${reportInfoPanel}\n\n${internalStatusPanel}`;
// Map the priority using the text from the sheet, or use the default
itemJson.priorityId = priorityMap[itemJson['嚴重度等級']] || priorityMap['_'];
// --- 6. Return the enhanced item ---
return itemJson;
使用上一步格式化好的內容,正式在 Jira 中建立一張 Bug 單。
- 新增一個 Jira 節點,設定好 API 憑證。
- Resource 選擇 Issue,Operation 選擇 Create。
- 選擇你的 Project 和 Issue Type (例如:Bug)。
- 在 Summary
欄位,使用表達式填入標題,例如:
=[Hospital] Prod - {{ $json['問題簡述'] }}。 - 點擊 Add Field,選擇 Description。在
Description 欄位中,使用表達式填入上一步產生的 Wiki Markup
字串:
={{ $json.jiraDescriptionString }}。 - 同樣地,點擊 Add Field -> Priority。在
Priority 欄位右側點擊「...」選擇 Add Expression,然後填入
={{ $json.priorityId }}。 - 你可以用同樣的方式設定 Assignee (負責人)、Reporter (回報人)、Labels (標籤) 等欄位。
- 同樣地,為此節點設定 On Error 為 "Continue (using error output)",並連接到另一個 Telegram 錯誤通知節點。
建立成功後,必須更新 Google Sheet 的狀態,以形成閉環,避免重複處理。
- 新增另一個 Google Sheets 節點。
- Operation 選擇 Update。
- 填寫與步驟 2 相同的 Spreadsheet ID 和 Sheet Name。
- 在 Key Column 中,填入你的 Google Sheet 中用來唯一識別每一列的欄位名稱,例如
row_number。 - 在 Fields to Update 區塊:
- Key:
Jira Link| Value (使用表達式):=https://YOUR_JIRA_DOMAIN/browse/{{ $('Create an issue').item.json.key }} - Key:
可Jira| Value:Done
- Key:
最後,我們將新建立的工單資訊,以易於閱讀的卡片形式發送到 Teams 頻道。
- (Power Automate) 建立一個 Power Automate 流程,觸發器選擇 "When an HTTP request is received",儲存後會產生一個 Webhook URL。
- (n8n) 新增一個 Code 節點,用來產生 Teams Adaptive Card 的 JSON 結構。這需要你熟悉 Adaptive Card 的語法,或使用 Adaptive Card Designer 來設計。
- (n8n) 新增一個 HTTP Request 節點。
- Method 設為 POST。
- 在 URL 欄位貼上你在 Power Automate 取得的 Webhook URL。
- Body Content Type 選擇 JSON。
- 在 Body 欄位,使用表達式填入上一步 Code 節點產生的 Adaptive Card JSON 變數。
當工作流執行到此處時,就會呼叫 Power Automate,進而將一張包含工單摘要、負責人、嚴重性等關鍵資訊的卡片發送到指定的 Teams 頻道。
成果與反思:將時間還給「人」
這個專案的價值,遠不止是省下幾分鐘的複製貼上。
-
時間價值的最大化 將團隊從重複性、低價值的行政工作中解放,讓團隊成員能專注於問題分析與用戶溝通。
-
品質與一致性 自動化確保了每張工單的品質與格式一致,降低了溝通成本,也讓問題追蹤與數據分析變得更加可靠。
-
主動的團隊協作 從「被動查詢」到「主動通知」,Teams 的即時通知機制,讓團隊的反應速度與協作效率提升了一個檔次。