一、 前言 💡
在現代開發流程中,資訊的即時性至關重要。Linear 作為頂尖的專案管理工具,雖然內建許多整合功能,但對於 Google Chat 的原生支援仍有優化空間。本文將分享如何利用免費的 Google Apps Script (GAS) 作為中轉站,將 Linear 的 Issue 動態、狀態變更及評論即時推送到 Google Chat 空間中。
二、 實作步驟詳解
1. 獲取 Google Chat Webhook 網址 🔗
首先,我們需要在目標 Google Chat 空間中建立接收端點:
進入 Google Chat 空間,點擊空間名稱旁的下拉選單,選擇「應用程式與整合」。
點擊「Webhook」,輸入名稱(如:Linear Bot)並儲存。
複製產生的 Webhook URL,我們後續程式碼會用到。
2. 撰寫 Google Apps Script 翻譯腳本 🛠️
/**
* Linear to Google Chat - 最終穩定版
* 功能:
* 1. 自動偵測 Issue 狀態變更 (從 Todo ➔ In Progress 等)
* 2. 顯示新評論內容
* 3. 過濾 Issue 刪除時伴隨的冗餘評論通知
*/
const GOOGLE_CHAT_WEBHOOK_URL = "你的_GOOGLE_CHAT_WEBHOOK_URL";
function doPost(e) {
try {
const payload = JSON.parse(e.postData.contents);
const action = payload.action;
const type = payload.type;
const data = payload.data;
const actor = payload.actor;
const url = payload.url || "";
const updatedAttrs = payload.updatedAttributes || {};
// 過濾邏輯:如果是「刪除評論」,通常是隨卡片一起刪除
if (type === "Comment" && action === "remove") {
return ContentService.createTextOutput("Skipped");
}
let messageText = "";
if (type === "Issue") {
const currentStateName = (data.state && data.state.name) || (data.status && data.status.name) || "未知";
let statusDisplay = currentStateName;
const isStateChanged = updatedAttrs.hasOwnProperty('stateId') || updatedAttrs.hasOwnProperty('statusId');
if (action === "update") {
if (isStateChanged) {
statusDisplay = `🔄 狀態更新:➔ *${currentStateName}*`;
} else {
statusDisplay = `${currentStateName} (內容更新)`;
}
}
if (action === "remove") {
messageText = `🗑️ *Linear Issue 已刪除*\n━━━━━━━━━━━━━━━━━━━━━━━━\n*標題*: ${data.title}\n*執行者*: ${actor.name}`;
} else {
const titleIcon = action === "create" ? "🚀" : "📝";
const actionLabel = action === "create" ? "新增 Issue" : "Issue 更新";
messageText = `${titleIcon} *Linear ${actionLabel}*\n━━━━━━━━━━━━━━━━━━━━━━━━\n*標題*: ${data.title}\n*狀態*: ${statusDisplay}\n*執行者*: ${actor.name}\n${url ? `*連結*: ${url}` : ""}`;
}
} else if (type === "Comment") {
messageText = `💬 *Linear 新評論*\n━━━━━━━━━━━━━━━━━━━━━━━━\n*內容*: ${data.body}\n*評論者*: ${actor.name}\n*連結*: ${url}`;
}
const options = {
"method": "post",
"contentType": "application/json",
"payload": JSON.stringify({ "text": messageText })
};
UrlFetchApp.fetch(GOOGLE_CHAT_WEBHOOK_URL, options);
return ContentService.createTextOutput("Success");
} catch (err) {
return ContentService.createTextOutput("Error: " + err.toString());
}
}
這段腳本不僅能抓取基本資訊,最重要的是它處理了 stateId 的邏輯判斷。在 Linear 的 Webhook 中,單純的更新(Update)與狀態變更(State Change)共享同一個 Action,我們透過檢查 updatedAttributes 屬性,成功讓通知變得更直觀。
由於 Linear 發出的資料格式與 Google Chat 要求的格式不同,我們需要一個「翻譯員」進行 Payload 的轉換:
前往 Google Apps Script 並建立新專案。
貼入解析邏輯程式碼。這段程式碼會判斷 Linear 的事件類型(Issue 或 Comment),並偵測 stateId 是否變動。
在程式碼頂部填入剛才取得的 Google Chat Webhook URL。
3. 部署網頁應用程式 🚀
這是讓 Linear 伺服器能夠存取腳本的關鍵步驟:
點擊右上角的「部署」 > 「新增部署」。
類型選擇「網頁應用程式」。
執行身分:選擇「我」。
誰有權存取:務必選擇 「所有人 (Anyone)」。
完成後,複製畫面上產生的 「網頁應用程式 URL」。
⚠️ 極重要注意事項:
Google Apps Script 的特性是,每次在編輯器修改程式碼後,必須點擊「部署」 > 「管理部署」並選擇「新版本 (New Version)」進行重新發布。發布後請務必重新複製新的網頁應用程式 URL,並同步更新至 Linear 的 Webhook 設定中,否則系統將持續執行舊版程式碼或導致串接失效。
4. 在 Linear 設定 Webhook 🎯
登入 Linear,進入 Settings > Integrations > Webhooks。
點擊「Add Webhook」,將剛才從 GAS 部署獲得的 URL 貼入。
勾選你感興趣的事件,例如 Issues 與 Comments。
點擊儲存,完成連通測試。
三、 成果驗證與預期表現 ✅
完成上述設定後,你可以嘗試在 Linear 進行以下動作測試通知效果:
新建 Issue:Google Chat 會彈出帶有 🚀 標籤的通知。
移動看板狀態:當 stateId 發生變動時,機器人會顯示 🔄 狀態更新:➔ [新狀態]。
發表評論:💬 標籤會帶出具體的評論內容、評論者名稱及直接跳轉的連結。
刪除 Issue:會顯示 🗑️ 標籤,程式碼已預設過濾掉隨卡片刪除而產生的冗餘評論通知,保持空間整潔。
四、 結語 📋
透過這套輕量化的免費方案,團隊成員不再需要頻繁切換視窗,就能在慣用的溝通工具中掌握開發進度。Google Apps Script 的靈活性也讓你可以根據需求,進一步客製化通知的文字排版或增加過濾特定團隊的邏輯。
留言
張貼留言