#看好了 GitHub Actions #我只示範一次 #GitHub Actions #Node.js #DevOps

用 GitHub Actions 把 Issue 同步到 Notion

Date
2024.10.01
Category
自動化
Read Time
15 min
Word
4.4k
Last Mod
2024.10.01
課程 2024.10.01 用 GitHub Actions 把 Issue 同步到 Notion

用 GitHub Actions 把 Issue 同步到 Notion

白居易在看到滿滿的 issue 後不經感嘆:「野火燒不盡,春風吹又生。」然後毅然決然地把 issue 同步到 Notion,這樣就不會忘記了。

今日範例程式:https://github.com/elvisdragonmao/2024-GitHub-Actions/tree/main/18

今天,我們將介紹如何編寫一個自定義的 GitHub Actions,將 GitHub 的 issue 自動同步到 Notion。這個工具將使你能夠將 GitHub 的問題跟踪和管理整合到 Notion 的資料庫中,讓問題管理更加高效。

Demo
Demo

實作

事前準備:建立 Notion 整合

首先請你參考昨天的步驟,建立一個 Notion 整合。請至 Notion Developers 建立一個新的整合,並取得 API 密鑰,然後整合至 Workspace。這個 API 密鑰將用於存取 Notion 的 API,以便將 GitHub 的 issue 同步到 Notion 中。

步驟 1:設定專案結構

首先,建立一個新的 GitHub 存儲庫來容納我們的自定義 Action。結構如下:

Text
github-issue-2-notion/├── action.yml├── script.js└── README.md

今天我們直接使用 Node.js 來編寫。

步驟 2:編寫 Action 配置文件

action.yml 文件中,定義 Action 的輸入、執行和輸出。以下是 action.yml 的內容:

YAML
name: "Sync GitHub Issues to Notion"description: "Synchronize GitHub issues to a Notion database"inputs:  repo:    description: "The GitHub repository (e.g., owner/repo)"    required: true  NOTION_API_KEY:    description: "The API key for the Notion integration"    required: true  NOTION_DATABASE_ID:    description: "The ID of the Notion database"    required: trueruns:  using: "node20"  steps:    - name: Run script      uses: actions/setup-node@v3      with:        node-version: "20"    - run: npm install    - run: node script.js      env:        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}        NOTION_API_KEY: ${{ inputs.NOTION_API_KEY }}        NOTION_DATABASE_ID: ${{ inputs.NOTION_DATABASE_ID }}

步驟 3:編寫 Node.js 腳本

script.js 文件中,編寫 Node.js 腳本來實現從 GitHub 取得 issue 並同步到 Notion。以下是 script.js 的完整內容:

JS
/** @format */const core = require("@actions/core");const axios = require("axios");const { markdownToBlocks } = require("@tryfabric/martian");async function main() {	const repo = core.getInput("repo");	const notionToken = core.getInput("NOTION_API_KEY");	const notionDatabaseId = core.getInput("NOTION_DATABASE_ID");	// GitHub Issues API URL	const issuesUrl = `https://api.github.com/repos/${repo}/issues?state=all`;	// Fetch issues from GitHub	const issuesResponse = await axios.get(issuesUrl, {		headers: {			"User-Agent": "request",			Authorization: `token ${process.env.GITHUB_TOKEN}`		}	});	for (const issue of issuesResponse.data) {		const issueId = issue.id;		const notionUrl = `https://api.notion.com/v1/databases/${notionDatabaseId}/query`;		// Check if the issue already exists in Notion		const notionResponse = await axios.post(			notionUrl,			{				filter: {					property: "ID",					number: {						equals: issueId					}				}			},			{				headers: {					Authorization: `Bearer ${notionToken}`,					"Notion-Version": "2022-06-28",					"Content-Type": "application/json"				}			}		);		const body = {			parent: { database_id: notionDatabaseId },			icon: {				emoji: "⚡"			},			properties: {				Name: {					title: [						{							text: {								content: issue.title							}						}					]				},				ID: {					number: issueId				},				State: {					select: {						name: issue.state.charAt(0).toUpperCase() + issue.state.slice(1)					}				},				Status: {					status: {						name: "Not started"					}				},				Labels: {					multi_select: issue.labels.map(label => ({						name: label.name					}))				},				URL: {					url: issue.html_url				}			},			children: issue.body != null ? markdownToBlocks(issue.body) : []		};		if (notionResponse.data.results.length > 0) {			console.log(`Issue ${issueId} already exists in Notion, updating it`);			// Update existing issue			const notionPageId = notionResponse.data.results[0].id;			delete body.properties.Status;			await axios.patch(`https://api.notion.com/v1/pages/${notionPageId}`, body, {				headers: {					Authorization: `Bearer ${notionToken}`,					"Content-Type": "application/json",					"Notion-Version": "2022-06-28"				}			});		} else {			console.log(`Creating new issue ${issueId} in Notion`);			// Create new issue			await axios.post("https://api.notion.com/v1/pages", body, {				headers: {					Authorization: `Bearer ${notionToken}`,					"Content-Type": "application/json",					"Notion-Version": "2022-06-28"				}			});			console.log(`Issue ${issueId} created in Notion`);		}	}}main().catch(error => {	console.error(error);	process.exit(1);});

這裡要來介紹一下裡面使用到的一些套件:

  • axios: 用於發送 HTTP 請求。
  • @tryfabric/martian: 用於將 Markdown 轉換為 Notion 的 block。
  • @actions/core: 用於存取 Action 的輸入和輸出。

步驟 4:設定 GitHub Secrets

在 GitHub 存儲庫的設定中,添加以下 Secrets:

  • NOTION_API_KEY: 你的 Notion API 密鑰。
  • NOTION_DATABASE_ID: 你的 Notion 資料庫 ID。

步驟 5:建立工作流程文件

在你的 GitHub 存儲庫的 .github/workflows 目錄下建立一個新的 YAML 文件,例如 sync-issues.yml,並添加以下內容:

YAML
name: Sync GitHub Issues to Notionon:  issues:    types: [opened, edited, deleted, closed, reopened]  workflow_dispatch:jobs:  sync:    runs-on: ubuntu-latest    steps:      - name: Checkout repository        uses: actions/checkout@v3      - name: Sync issues to Notion        uses: ./path-to-your-action # 使用自定義 Action 的路徑        with:          repo: ${{ github.repository }}          NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}          NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}

這個工作流程將在 GitHub 的 issue 有變化時觸發,並運行我們的自定義 Action 來同步 issue 到 Notion。

小結

今天我們探討了如何編寫一個 GitHub Actions 來將 GitHub 的 issue 同步到 Notion。通過這個實踐,我們掌握了如何使用 Node.js 和 GitHub Actions 來自動化從 GitHub 取得問題並更新 Notion 資料庫的過程。希望這篇教程能幫助你更高效地管理問題並保持項目組織的井然有序。

About me

毛哥EM

這裡是毛哥EM,一隻全端開發龍還有英文辯士。
熱愛開源、音樂、設計、獸迷文化,專研人機互動與人工智慧。

本部落格皆屬原創文章,採 CC BY-SA 4.0 授權,
轉載請註明來自毛哥EM資訊密技。
這篇文章對你有幫助嗎? 考慮幫我買瓶 Red Bull?

毛哥EM 角色插圖

Comments

留言區