Linear 整合 Google Chat 教學:利用 Webhooks 與 Google Apps Script 打造自動化通知系統

一、 前言 💡

在現代開發流程中,資訊的即時性至關重要。Linear 作為頂尖的專案管理工具,雖然內建許多整合功能,但對於 Google Chat 的原生支援仍有優化空間。本文將分享如何利用免費的 Google Apps Script (GAS) 作為中轉站,將 Linear 的 Issue 動態、狀態變更及評論即時推送到 Google Chat 空間中。

二、 實作步驟詳解

1. 獲取 Google Chat Webhook 網址 🔗

首先,我們需要在目標 Google Chat 空間中建立接收端點:

  1. 進入 Google Chat 空間,點擊空間名稱旁的下拉選單,選擇「應用程式與整合」。

  2. 點擊「Webhook」,輸入名稱(如:Linear Bot)並儲存。

  3. 複製產生的 Webhook URL,我們後續程式碼會用到。

2. 撰寫 Google Apps Script 翻譯腳本 🛠️

Linear_To_GChat.gs
/**
 * 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 的轉換:

  1. 前往 Google Apps Script 並建立新專案。

  2. 貼入解析邏輯程式碼。這段程式碼會判斷 Linear 的事件類型(Issue 或 Comment),並偵測 stateId 是否變動。

  3. 在程式碼頂部填入剛才取得的 Google Chat Webhook URL。

3. 部署網頁應用程式 🚀

這是讓 Linear 伺服器能夠存取腳本的關鍵步驟:

  1. 點擊右上角的「部署」 > 「新增部署」。

  2. 類型選擇「網頁應用程式」。

  3. 執行身分:選擇「我」。

  4. 誰有權存取:務必選擇 「所有人 (Anyone)」

  5. 完成後,複製畫面上產生的 「網頁應用程式 URL」


⚠️ 極重要注意事項: Google Apps Script 的特性是,每次在編輯器修改程式碼後,必須點擊「部署」 > 「管理部署」並選擇「新版本 (New Version)」進行重新發布。發布後請務必重新複製新的網頁應用程式 URL,並同步更新至 Linear 的 Webhook 設定中,否則系統將持續執行舊版程式碼或導致串接失效。


4. 在 Linear 設定 Webhook 🎯

  1. 登入 Linear,進入 Settings > Integrations > Webhooks

  2. 點擊「Add Webhook」,將剛才從 GAS 部署獲得的 URL 貼入。

  3. 勾選你感興趣的事件,例如 IssuesComments

  4. 點擊儲存,完成連通測試。

三、 成果驗證與預期表現 ✅

完成上述設定後,你可以嘗試在 Linear 進行以下動作測試通知效果:

  • 新建 Issue:Google Chat 會彈出帶有 🚀 標籤的通知。

  • 移動看板狀態:當 stateId 發生變動時,機器人會顯示 🔄 狀態更新:➔ [新狀態]

  • 發表評論:💬 標籤會帶出具體的評論內容、評論者名稱及直接跳轉的連結。

  • 刪除 Issue:會顯示 🗑️ 標籤,程式碼已預設過濾掉隨卡片刪除而產生的冗餘評論通知,保持空間整潔。

四、 結語 📋

透過這套輕量化的免費方案,團隊成員不再需要頻繁切換視窗,就能在慣用的溝通工具中掌握開發進度。Google Apps Script 的靈活性也讓你可以根據需求,進一步客製化通知的文字排版或增加過濾特定團隊的邏輯。

留言

熱門文章