司馬遷如果使用 GitHub Actions 就可以自動更新《史記》了。

在這篇教程中,我們將探討如何使用 GitHub Actions 自動生成和更新 Markdown 文件。

我們要使用 Actions 自動從 fonts.json 文件中生成一個格式化的字體列表並更新 README.md 文件。這包括讀取 JSON 文件內容、生成 Markdown 表格,以及在 README 文件中更新這些內容。

今日範例程式:https://github.com/Edit-Mr/2024-GitHub-Actions/tree/main/20

1. 背景與目標

emfont 是一個免費的繁體中文 Web Font 服務。在之前字體列表存放在 Database/fonts.json 文件中,我們希望自動更新 README.md 文件中的字體列表。這樣可以確保文檔始終保持最新狀態,並且減少了手動更新的工作量。

表格效果
表格效果

emfont GitHub: https://github.com/emfont/emfont

今天我們要來復刻這個專案。首先請你準備 fonts.json。你可以透過上面的 GitHub 連結下載。這個 JSON 文件包含了字體的詳細信息,例如名稱、風格、字種、版本、許可證和來源。以下是 JSON 文件的一部分內容:

1{
2
3    "975HazyGoSC":{
4        "name": { "zh": "975 朦胧黑体", "en": "975 Hazy Go SC" },
5        "style": "normal",
6        "weight": [200,300,400,500,600],
7        "class": "emfont-975HazyGoSC",
8        "version": "v2.01",
9        "license": "OFL-1.1",
10        "source": "https://github.com/lxgw/975HazyGo"
11    },
12    "CEFFontsCJK":{
13        "name": { "zh": "快去写作业 CJK", "en": "CEF Fonts CJK" },
14        "style": ["normal","mono"],
15        "weight": [400],
16        "class": "emfont-CEFFontsCJK",
17        "version": "v2.16",
18        "license": "OFL-1.1",
19        "source": "https://github.com/Partyb0ssishere/cef-fonts-cjk "
20    },
21    "ChenYuLuoYan":
22    {
23        "name": { "zh": "辰宇落雁體", "en": "ChenYuLuoYan Thin" },
24        "style": "normal",
25        "weight": [400],
26        "class": "emfont-ChenYuLuoYan",
27        "version": "v1.0",
28        "license": "OFL-1.1",
29        "source": "https://github.com/Chenyu-otf/chenyuluoyan_thin"
30    },

接下來我們要來準備 README.md。這個文件將會包含字體列表。我們將在 之間插入 Markdown 表格。

1# emfont
2
3免費的繁體中文 Web Font 服務。
4
5> 如果你喜歡這個項目,認同我們的理念,歡迎在 GitHub 給我們 ⭐ 一顆星星,分享給你的朋友,或是留下你寶貴的意見。
6
7## 字體列表
8
9
10
11

設定 GitHub Actions

我們將設定 GitHub Actions 自動更新 README.md 文件。當 Database/fonts.json 文件有變動時,工作流程會自動執行,生成新的 Markdown 表格並更新 README 文件。

步驟 1:創建 GitHub Actions 工作流程

.github/workflows 目錄下創建一個新的 YAML 文件,例如 update-font-list.yml,並添加以下內容:

1name: Update Font List
2
3on:
4    push:
5        paths:
6            - "Database/fonts.json"
7    workflow_dispatch:
8
9jobs:
10    update-readme:
11        runs-on: ubuntu-latest
12
13        steps:
14            - name: Checkout repository
15              uses: actions/checkout@v3
16
17            - name: Set up Node.js
18              uses: actions/setup-node@v3
19              with:
20                  node-version: "20"
21
22            - name: Update README.md
23              run: node src/workflows/update-readme.js
24
25            - name: Check for changes
26              id: git-diff
27              run: |
28                  git diff --quiet || echo "::set-output name=changes::true"
29
30            - name: Commit and Push Changes
31              run: |
32                  if [[ "${{ steps.git-diff.outputs.changes }}" == "true" ]]; then
33                    git config --local user.email "action@github.com"
34                    git config --local user.name "GitHub Actions"
35                    git add .
36                    git commit -m "📋 Update font list"
37                    git push
38                  else
39                    echo "No changes to commit. Skipping push."
40                  fi

這個工作流程會在 Database/fonts.json 文件發生變更時自動執行,並更新 README.md 文件中的字體列表。

今天沒有要使用第三方套件,所以不需要安裝,也不需要設定 GitHub Secrets。

步驟 2:編寫生成 Markdown 的腳本

src/workflows 目錄下創建 update-readme.js 文件,並添加以下內容:

1import fs from "fs";
2import path from "path";
3import { fileURLToPath } from "url";
4
5// Convert __dirname to work with ES modules
6const __filename = fileURLToPath(import.meta.url);
7const __dirname = path.dirname(__filename);
8
9const fontsFilePath = path.join(
10    __dirname,
11    "..",
12    "..",
13    "Database",
14    "fonts.json"
15);
16const readmeFilePath = path.join(__dirname, "..", "..", "README.md");
17
18// Read and parse the fonts.json file
19const fontsData = JSON.parse(fs.readFileSync(fontsFilePath, "utf8"));
20
21// Function to convert JSON data to a markdown table
22function generateMarkdownTable(data) {
23    const headers = [
24        "Font ID",
25        "中文名稱",
26        "英文名稱",
27        "字體風格",
28        "字種",
29        "Class",
30        "版本",
31        "許可證",
32        "來源"
33    ];
34    const rows = Object.entries(data).map(([id, details]) => {
35        const {
36            name,
37            style,
38            weight,
39            class: className,
40            version,
41            license,
42            source
43        } = details;
44        return [
45            id,
46            name.zh || "",
47            name.en || "",
48            style || "",
49            weight.join(", ") || "",
50            className || "",
51            version || "",
52            license || "",
53            source || ""
54        ].join(" | ");
55    });
56
57    const table = [
58        headers.join(" | "),
59        headers.map(() => "---").join(" | "),
60        ...rows
61    ].join("\n");
62
63    return table;
64}
65
66// Generate the markdown table
67const markdownTable = generateMarkdownTable(fontsData);
68
69// Read the current README.md file
70const readmeContent = fs.readFileSync(readmeFilePath, "utf8");
71
72// Update the section of the README.md file where the table should be inserted
73const updatedReadmeContent = readmeContent.replace(
74    /[\s\S]*/,
75    `\n${markdownTable}\n`
76);
77
78// Write the updated README.md file
79fs.writeFileSync(readmeFilePath, updatedReadmeContent);
80
81console.log("README.md has been updated");

腳本解析

  • 讀取 JSON 文件: 腳本從 Database/fonts.json 讀取字體數據。
  • 生成 Markdown 表格: generateMarkdownTable 函數將 JSON 數據轉換為 Markdown 格式的表格。
  • 更新 README 文件: 腳本讀取 README.md 文件,並將生成的 Markdown 表格插入到標記為 之間的區域。

小結

通過今天的教程,我們探討了如何使用 GitHub Actions 自動生成和更新 Markdown 文件。我們通過編寫腳本來從 JSON 文件生成 Markdown 表格,並將其更新到 README.md 文件中。這樣的自動化流程能夠確保文檔始終保持最新狀態,並且減少了手動更新的工作量。

毛哥EM

一位喜歡把簡單的事,做得不簡單的高三生。