<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Blog維護 on Tarragon</title><link>https://tarrragon.github.io/blog/tags/blog%E7%B6%AD%E8%AD%B7/</link><description>Recent content in Blog維護 on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Wed, 06 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/blog%E7%B6%AD%E8%AD%B7/index.xml" rel="self" type="application/rss+xml"/><item><title>本 blog 專案的 GitHub Actions workflow</title><link>https://tarrragon.github.io/blog/ci/blog-project-deploy/github-actions-workflows/</link><pubDate>Wed, 06 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ci/blog-project-deploy/github-actions-workflows/</guid><description>&lt;p>本 blog 的 GitHub Actions workflow 負責把內容檢查、瀏覽器回歸測試、Hugo 發布與 Claude 協作分成不同自動化流程。每條 workflow 都是一個獨立入口；維護時要先分清楚它是在保護內容品質、使用者行為、發布產物，還是協作流程。&lt;/p>
&lt;h2 id="workflow-總覽">Workflow 總覽&lt;/h2>
&lt;p>本專案目前有五條 workflow。三條屬於 CI / CD 主流程，兩條屬於 Claude 協作輔助流程。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>Workflow&lt;/th>
 &lt;th>檔案&lt;/th>
 &lt;th>觸發條件&lt;/th>
 &lt;th>核心責任&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>md-check&lt;/code>&lt;/td>
 &lt;td>&lt;code>.github/workflows/md-check.yml&lt;/code>&lt;/td>
 &lt;td>push / pull request 到 &lt;code>main&lt;/code>&lt;/td>
 &lt;td>檢查 content Markdown 契約&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>Playwright tests&lt;/code>&lt;/td>
 &lt;td>&lt;code>.github/workflows/playwright.yml&lt;/code>&lt;/td>
 &lt;td>push / pull request 到 &lt;code>main&lt;/code>&lt;/td>
 &lt;td>驗證瀏覽器層行為與版面回歸&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>Deploy Hugo site to Pages&lt;/code>&lt;/td>
 &lt;td>&lt;code>.github/workflows/deploy.yml&lt;/code>&lt;/td>
 &lt;td>push 到 &lt;code>main&lt;/code>&lt;/td>
 &lt;td>建置 Hugo、產生搜尋索引並部署&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>Claude Code&lt;/code>&lt;/td>
 &lt;td>&lt;code>.github/workflows/claude.yml&lt;/code>&lt;/td>
 &lt;td>issue / comment / review 叫 Claude&lt;/td>
 &lt;td>讓 Claude 讀 issue、PR 與 CI 結果&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>Claude Code Review&lt;/code>&lt;/td>
 &lt;td>&lt;code>.github/workflows/claude-code-review.yml&lt;/code>&lt;/td>
 &lt;td>PR opened / synchronize 等事件&lt;/td>
 &lt;td>對 PR 進行 Claude code review&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>這張表的責任是提供入口。看到 GitHub Actions 紅燈時，先對照 workflow 名稱，把失敗歸到內容檢查、瀏覽器測試、部署或協作流程。&lt;/p>
&lt;h2 id="md-check">&lt;code>md-check&lt;/code>&lt;/h2>
&lt;p>&lt;code>md-check&lt;/code> 的責任是讓 &lt;code>content/&lt;/code> 裡的 Markdown 維持同一套結構契約。它會先用 Go build 出 &lt;code>scripts/mdtools&lt;/code>，再依序執行 formatter 檢查、lint 與卡片連結檢查。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">md-check&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">on&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">push&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">main]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pull_request&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">branches&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">main]&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>這條 workflow 的核心步驟是：&lt;/p>
&lt;ol>
&lt;li>&lt;code>actions/checkout@v6&lt;/code>&lt;/li>
&lt;li>&lt;code>actions/setup-go@v6&lt;/code>&lt;/li>
&lt;li>&lt;code>go build -o ../../bin/mdtools&lt;/code>&lt;/li>
&lt;li>&lt;code>./bin/mdtools fmt --check content/&lt;/code>&lt;/li>
&lt;li>&lt;code>./bin/mdtools lint content/&lt;/code>&lt;/li>
&lt;li>&lt;code>./bin/mdtools cards content/&lt;/code>&lt;/li>
&lt;/ol>
&lt;p>&lt;code>md-check&lt;/code> 失敗時，下一步是回本機跑同一組命令。&lt;code>fmt --check&lt;/code> 失敗代表格式可由 &lt;code>fmt --fix&lt;/code> 修正；&lt;code>lint&lt;/code> 失敗代表標題、front matter、URL、code block 等結構契約不符；&lt;code>cards&lt;/code> 失敗代表卡片連結、orphan 或 K4 規則需要修。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">./bin/mdtools fmt --check content/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">./bin/mdtools lint content/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">./bin/mdtools cards content/&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>維護這條 workflow 時，規則來源要和 &lt;a href="https://tarrragon.github.io/blog/posts/blog-markdown-%E5%AF%AB%E4%BD%9C%E8%A6%8F%E7%AF%84%E8%88%87-mdtools-%E6%AA%A2%E6%9F%A5/" data-link-title="Blog Markdown 寫作規範與 mdtools 檢查" data-link-desc="本 blog 的 Markdown 排版規範權威契約。涵蓋 H1 禁用、MD024 siblings_only、反釣魚 TLD 校驗、卡片雙向完整性、front matter schema；改規則時要與 scripts/mdtools 實作同步。">Blog Markdown 寫作規範與 mdtools 檢查&lt;/a> 對齊。改 &lt;code>scripts/mdtools/internal/rules/&lt;/code> 時，也要同步更新規範文章，避免 CI 行為和文件描述分叉。&lt;/p>
&lt;h2 id="playwright-tests">&lt;code>Playwright tests&lt;/code>&lt;/h2>
&lt;p>&lt;code>Playwright tests&lt;/code> 的責任是驗證使用者可見行為。它會先建出完整 Hugo site 與 Pagefind index，再用 Chromium 驗證搜尋、版面與互動。&lt;/p></description><content:encoded><![CDATA[<p>本 blog 的 GitHub Actions workflow 負責把內容檢查、瀏覽器回歸測試、Hugo 發布與 Claude 協作分成不同自動化流程。每條 workflow 都是一個獨立入口；維護時要先分清楚它是在保護內容品質、使用者行為、發布產物，還是協作流程。</p>
<h2 id="workflow-總覽">Workflow 總覽</h2>
<p>本專案目前有五條 workflow。三條屬於 CI / CD 主流程，兩條屬於 Claude 協作輔助流程。</p>
<table>
  <thead>
      <tr>
          <th>Workflow</th>
          <th>檔案</th>
          <th>觸發條件</th>
          <th>核心責任</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>md-check</code></td>
          <td><code>.github/workflows/md-check.yml</code></td>
          <td>push / pull request 到 <code>main</code></td>
          <td>檢查 content Markdown 契約</td>
      </tr>
      <tr>
          <td><code>Playwright tests</code></td>
          <td><code>.github/workflows/playwright.yml</code></td>
          <td>push / pull request 到 <code>main</code></td>
          <td>驗證瀏覽器層行為與版面回歸</td>
      </tr>
      <tr>
          <td><code>Deploy Hugo site to Pages</code></td>
          <td><code>.github/workflows/deploy.yml</code></td>
          <td>push 到 <code>main</code></td>
          <td>建置 Hugo、產生搜尋索引並部署</td>
      </tr>
      <tr>
          <td><code>Claude Code</code></td>
          <td><code>.github/workflows/claude.yml</code></td>
          <td>issue / comment / review 叫 Claude</td>
          <td>讓 Claude 讀 issue、PR 與 CI 結果</td>
      </tr>
      <tr>
          <td><code>Claude Code Review</code></td>
          <td><code>.github/workflows/claude-code-review.yml</code></td>
          <td>PR opened / synchronize 等事件</td>
          <td>對 PR 進行 Claude code review</td>
      </tr>
  </tbody>
</table>
<p>這張表的責任是提供入口。看到 GitHub Actions 紅燈時，先對照 workflow 名稱，把失敗歸到內容檢查、瀏覽器測試、部署或協作流程。</p>
<h2 id="md-check"><code>md-check</code></h2>
<p><code>md-check</code> 的責任是讓 <code>content/</code> 裡的 Markdown 維持同一套結構契約。它會先用 Go build 出 <code>scripts/mdtools</code>，再依序執行 formatter 檢查、lint 與卡片連結檢查。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">md-check</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">main]</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w">  </span><span class="nt">pull_request</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">main]</span></span></span></code></pre></div><p>這條 workflow 的核心步驟是：</p>
<ol>
<li><code>actions/checkout@v6</code></li>
<li><code>actions/setup-go@v6</code></li>
<li><code>go build -o ../../bin/mdtools</code></li>
<li><code>./bin/mdtools fmt --check content/</code></li>
<li><code>./bin/mdtools lint content/</code></li>
<li><code>./bin/mdtools cards content/</code></li>
</ol>
<p><code>md-check</code> 失敗時，下一步是回本機跑同一組命令。<code>fmt --check</code> 失敗代表格式可由 <code>fmt --fix</code> 修正；<code>lint</code> 失敗代表標題、front matter、URL、code block 等結構契約不符；<code>cards</code> 失敗代表卡片連結、orphan 或 K4 規則需要修。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">./bin/mdtools fmt --check content/
</span></span><span class="line"><span class="ln">2</span><span class="cl">./bin/mdtools lint content/
</span></span><span class="line"><span class="ln">3</span><span class="cl">./bin/mdtools cards content/</span></span></code></pre></div><p>維護這條 workflow 時，規則來源要和 <a href="/blog/posts/blog-markdown-%E5%AF%AB%E4%BD%9C%E8%A6%8F%E7%AF%84%E8%88%87-mdtools-%E6%AA%A2%E6%9F%A5/" data-link-title="Blog Markdown 寫作規範與 mdtools 檢查" data-link-desc="本 blog 的 Markdown 排版規範權威契約。涵蓋 H1 禁用、MD024 siblings_only、反釣魚 TLD 校驗、卡片雙向完整性、front matter schema；改規則時要與 scripts/mdtools 實作同步。">Blog Markdown 寫作規範與 mdtools 檢查</a> 對齊。改 <code>scripts/mdtools/internal/rules/</code> 時，也要同步更新規範文章，避免 CI 行為和文件描述分叉。</p>
<h2 id="playwright-tests"><code>Playwright tests</code></h2>
<p><code>Playwright tests</code> 的責任是驗證使用者可見行為。它會先建出完整 Hugo site 與 Pagefind index，再用 Chromium 驗證搜尋、版面與互動。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Playwright tests</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">main]</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w">  </span><span class="nt">pull_request</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">main]</span></span></span></code></pre></div><p>這條 workflow 的核心步驟是：</p>
<ol>
<li>checkout，並包含 submodules</li>
<li>安裝 Hugo <code>0.148.2</code> extended</li>
<li>安裝 Node <code>24</code></li>
<li><code>npm ci</code></li>
<li><code>npx playwright install --with-deps chromium</code></li>
<li><code>make site</code></li>
<li><code>npx playwright test</code></li>
<li>失敗時上傳 <code>playwright-report/</code></li>
</ol>
<p><code>make site</code> 是這條 workflow 的關鍵前置條件。它會產生 Hugo 靜態檔與三份 Pagefind index：<code>pagefind</code>、<code>pagefind-title</code>、<code>pagefind-content</code>。如果只跑 <code>hugo --minify</code> 就跑 Playwright，搜尋測試會因為缺少 index 而失敗。</p>
<p>Playwright 失敗時，下一步是下載 <code>playwright-report</code> 或讀 error context。若失敗發生在搜尋頁，先確認 <code>make site</code> 是否完整成功；若失敗發生在版面，先看 screenshot、bounding box 或 computed style；若失敗發生在互動，先看 selector 是否仍對準真實 DOM。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">make site
</span></span><span class="line"><span class="ln">2</span><span class="cl">npm test</span></span></code></pre></div><p>維護這條 workflow 時，測試要守使用者行為，不應只守 implementation detail。像 TOC RWD 這類版面行為，可以用 viewport 測試固定桌面、筆電與手機三種狀態。</p>
<h2 id="deploy-hugo-site-to-pages"><code>Deploy Hugo site to Pages</code></h2>
<p><code>Deploy Hugo site to Pages</code> 的責任是把 <code>main</code> 上的內容建置成 GitHub Pages artifact 並部署。它只在 push 到 <code>main</code> 時觸發，不在 pull request 上部署。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Deploy Hugo site to Pages</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">  </span><span class="nt">push</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">    </span><span class="nt">branches</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w">      </span>- <span class="l">main</span></span></span></code></pre></div><p>這條 workflow 有兩個 job：</p>
<table>
  <thead>
      <tr>
          <th>Job</th>
          <th>責任</th>
          <th>關鍵設定</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>build</code></td>
          <td>checkout、Hugo build、Pagefind、artifact</td>
          <td><code>runs-on: ubuntu-latest</code></td>
      </tr>
      <tr>
          <td><code>deploy</code></td>
          <td>發布 GitHub Pages</td>
          <td><code>needs: build</code></td>
      </tr>
  </tbody>
</table>
<p><code>build</code> job 會先跑 <code>hugo --minify</code>，並把輸出寫到 <code>hugo-build-output.txt</code>。目前它設了 <code>continue-on-error: true</code>，所以 Hugo build 失敗時會進入 Claude Debug 步驟，嘗試讓 Claude 分析錯誤並 commit 修復。</p>
<p><code>Fail if build was not fixed</code> 是第二道保護。若原本 Hugo build 失敗，workflow 會重新跑一次 <code>hugo --minify</code>；如果 Claude 沒修好，這一步會讓 workflow 停止。</p>
<p>Pagefind index 會在 Hugo build 後產生：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">npx -y pagefind --site public --root-selector main
</span></span><span class="line"><span class="ln">2</span><span class="cl">npx -y pagefind --site public --root-selector <span class="s2">&#34;article.article-content &gt; h1&#34;</span> --output-subdir pagefind-title
</span></span><span class="line"><span class="ln">3</span><span class="cl">npx -y pagefind --site public --root-selector <span class="s2">&#34;.article-body&#34;</span> --output-subdir pagefind-content</span></span></code></pre></div><p>Deploy 失敗時，下一步先分層判讀。若 <code>build</code> job 失敗，回到 Hugo 或 Pagefind；若 <code>Upload artifact</code> 成功但 <code>deploy</code> job 失敗，檢查 Pages environment、permission、artifact 與 GitHub Pages 設定。</p>
<p>這條 workflow 目前的注意事項是：deploy workflow 自己沒有直接 <code>needs</code> <code>md-check</code> 或 <code>Playwright tests</code>，因為它們是獨立 workflow。這是本專案目前的實際邊界；gate 設計原理見 <a href="../../ci-gate-workflow-boundary/">CI gate 與 workflow 邊界</a>。</p>
<h2 id="claude-code"><code>Claude Code</code></h2>
<p><code>Claude Code</code> 的責任是提供互動式 Claude 協作入口。它不會在每次 push 自動修程式，而是在 issue、comment 或 review 內容包含 <code>@claude</code> 時觸發。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w">  </span><span class="nt">issue_comment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">    </span><span class="nt">types</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">created]</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w">  </span><span class="nt">pull_request_review_comment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w">    </span><span class="nt">types</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">created]</span><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w">  </span><span class="nt">issues</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="w">    </span><span class="nt">types</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">opened, assigned]</span><span class="w">
</span></span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="w">  </span><span class="nt">pull_request_review</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="w">    </span><span class="nt">types</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">submitted]</span></span></span></code></pre></div><p>這條 workflow 的 gate 寫在 job <code>if</code>。只有以下情境會真正執行：</p>
<ul>
<li>issue comment 包含 <code>@claude</code></li>
<li>pull request review comment 包含 <code>@claude</code></li>
<li>pull request review body 包含 <code>@claude</code></li>
<li>issue title 或 body 包含 <code>@claude</code></li>
</ul>
<p>這條 workflow 給 Claude <code>actions: read</code> 權限，讓它能讀 PR 上的 CI 結果。這對「請 Claude 看 CI 為什麼失敗」很重要，因為 Claude 需要讀 workflow run、job log 或 check 結果才能判斷。</p>
<p>維護這條 workflow 時，重點是權限最小化。它目前給的是 <code>contents: read</code>、<code>pull-requests: read</code>、<code>issues: read</code>、<code>id-token: write</code>、<code>actions: read</code>，適合互動分析；若未來要讓 Claude 直接 commit，才需要重新評估寫入權限與保護條件。</p>
<h2 id="claude-code-review"><code>Claude Code Review</code></h2>
<p><code>Claude Code Review</code> 的責任是在 PR 事件發生時跑 Claude code review。它和 <code>Claude Code</code> 不同，前者是 PR review automation，後者是被 <code>@claude</code> 叫起來的互動入口。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="ln">1</span><span class="cl"><span class="nt">on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w">  </span><span class="nt">pull_request</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">    </span><span class="nt">types</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">opened, synchronize, ready_for_review, reopened]</span></span></span></code></pre></div><p>這條 workflow 使用 <code>code-review@claude-code-plugins</code>，prompt 是：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}</span></span></code></pre></div><p>它的責任是提供 review 視角。Claude review 可以指出風險、邏輯問題或測試缺口；真正阻擋合併與發布的責任仍在 <a href="/blog/ci/knowledge-cards/required-checks/" data-link-title="Required Checks" data-link-desc="說明 pull request 的必要檢查如何作為合併 gate">Required Checks</a>、測試 workflow 與 deploy gate。</p>
<p>維護這條 workflow 時，可以依 PR 類型決定是否加 path filter。若未來只想在程式碼或 workflow 變更時觸發，可打開 <code>paths</code> 設定；若希望文章內容也被 review，就維持目前全 PR 觸發。</p>
<h2 id="本專案的發布阻擋邊界">本專案的發布阻擋邊界</h2>
<p>本 blog 的發布阻擋邊界需要同時看 YAML 與 GitHub repository 設定。這一節只記錄本專案目前能從 YAML 判讀出的事實；required checks、environment protection 與 artifact handoff 的原理不在本頁展開。</p>
<p>目前從 YAML 可直接確認的阻擋關係是：</p>
<table>
  <thead>
      <tr>
          <th>關係</th>
          <th>是否在 YAML 中明確存在</th>
          <th>說明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>deploy</code> 等 <code>build</code></td>
          <td>是</td>
          <td><code>deploy</code> job 有 <code>needs: build</code></td>
      </tr>
      <tr>
          <td><code>deploy</code> 等 <code>md-check</code></td>
          <td>否</td>
          <td><code>md-check</code> 是另一條 workflow</td>
      </tr>
      <tr>
          <td><code>deploy</code> 等 Playwright</td>
          <td>否</td>
          <td><code>Playwright tests</code> 是另一條 workflow</td>
      </tr>
      <tr>
          <td>PR 需要通過測試才能合併</td>
          <td>需查 repository 設定</td>
          <td>需要看 GitHub branch protection 設定</td>
      </tr>
      <tr>
          <td>Pages deploy 需要人工審核</td>
          <td>需查 environment 設定</td>
          <td>需要看 GitHub Pages environment protection 設定</td>
      </tr>
  </tbody>
</table>
<p>若日後發現測試紅燈但 Pages 仍發布，本頁只負責指出目前 workflow 邊界；具體改法回到 <a href="../../ci-gate-workflow-boundary/">CI gate 與 workflow 邊界</a> 判斷，並對照 <a href="/blog/ci/knowledge-cards/required-checks/" data-link-title="Required Checks" data-link-desc="說明 pull request 的必要檢查如何作為合併 gate">Required Checks</a> 與 <a href="/blog/ci/knowledge-cards/environment-protection/" data-link-title="Environment Protection" data-link-desc="說明目標環境的審核、權限與放行條件如何保護發布">Environment Protection</a>。</p>
<h2 id="失敗時的維護路由">失敗時的維護路由</h2>
<p>失敗時的維護路由要先定位 workflow，再定位 job，再回到本機重現。這能避免在錯誤層修錯問題。</p>
<table>
  <thead>
      <tr>
          <th>紅燈位置</th>
          <th>優先看什麼</th>
          <th>本機重現命令</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>md-check</code></td>
          <td>mdtools 訊息</td>
          <td><code>./bin/mdtools lint content/</code></td>
      </tr>
      <tr>
          <td><code>Playwright tests</code></td>
          <td><code>playwright-report</code> / error context</td>
          <td><code>make site</code> 後 <code>npm test</code></td>
      </tr>
      <tr>
          <td><code>Deploy</code> 的 Hugo build</td>
          <td><code>hugo-build-output.txt</code></td>
          <td><code>hugo --minify</code></td>
      </tr>
      <tr>
          <td><code>Deploy</code> 的 Pagefind</td>
          <td>Pagefind command output</td>
          <td><code>make site</code></td>
      </tr>
      <tr>
          <td><code>Deploy</code> 的 Pages step</td>
          <td>artifact / permission / environment</td>
          <td>GitHub Actions UI + Pages 設定</td>
      </tr>
      <tr>
          <td><code>Claude Code</code></td>
          <td>secret / permission / trigger <code>if</code></td>
          <td>檢查 <code>@claude</code> 觸發文字與 secrets</td>
      </tr>
      <tr>
          <td><code>Claude Code Review</code></td>
          <td>plugin marketplace / token</td>
          <td>檢查 PR event、secret 與 action log</td>
      </tr>
  </tbody>
</table>
<p>這份路由也可以當維護 checklist。新增 workflow 時，至少要補三件事：觸發條件、失敗時看哪個 artifact 或 log、本機要用哪條命令重現。</p>
<h2 id="本專案維護注意事項">本專案維護注意事項</h2>
<p>本專案維護注意事項的責任是記錄和目前 YAML 直接相關的操作提醒。這些提醒隨 workflow 實作改變而更新，不承擔通用 CI 設計原理。</p>
<ul>
<li><code>Playwright tests</code> 依賴 <code>make site</code> 產生 Pagefind index；搜尋測試失敗時先確認 production build 是否完整。</li>
<li><code>deploy.yml</code> 的 Hugo build 使用 <code>continue-on-error: true</code>，後面用 Claude Debug 與 retry build 接住失敗。</li>
<li><code>Claude Code</code> 目前是 read-oriented 互動入口；若未來要寫入 repo，需要重新審核 permission。</li>
<li><code>.github/workflows/*.yml</code> 有實作變更時，要同步更新本頁，讓維護入口維持可信。</li>
</ul>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>CI 紅燈處理流程：讀 <a href="../../github-actions-failure-flow/">CI 失敗到修復發布流程</a>。</li>
<li>CI gate 設計原理：讀 <a href="../../ci-gate-workflow-boundary/">CI gate 與 workflow 邊界</a>。</li>
<li>CI 在可靠性模組的位置：讀 <a href="/blog/backend/06-reliability/ci-pipeline/" data-link-title="6.1 CI pipeline" data-link-desc="CI pipeline 的分層策略、artifact 管理、flaky 治理與 release gate 輸入">6.1 CI pipeline</a>。</li>
<li>發布 gate 設計：讀 <a href="/blog/backend/06-reliability/release-gate/" data-link-title="6.8 Release Gate 與變更節奏" data-link-desc="把驗證、migration、相容性納入放行判準">6.8 Release Gate 與變更節奏</a>。</li>
<li>Markdown 檢查規則：讀 <a href="/blog/posts/blog-markdown-%E5%AF%AB%E4%BD%9C%E8%A6%8F%E7%AF%84%E8%88%87-mdtools-%E6%AA%A2%E6%9F%A5/" data-link-title="Blog Markdown 寫作規範與 mdtools 檢查" data-link-desc="本 blog 的 Markdown 排版規範權威契約。涵蓋 H1 禁用、MD024 siblings_only、反釣魚 TLD 校驗、卡片雙向完整性、front matter schema；改規則時要與 scripts/mdtools 實作同步。">Blog Markdown 寫作規範與 mdtools 檢查</a>。</li>
</ul>
]]></content:encoded></item><item><title>本 blog 專案部署</title><link>https://tarrragon.github.io/blog/ci/blog-project-deploy/</link><pubDate>Wed, 06 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ci/blog-project-deploy/</guid><description>&lt;p>本 blog 專案部署是前端靜態站部署的一個具體案例。這個資料夾只記錄本專案實際使用的 Hugo、Pagefind、Playwright、GitHub Pages 與 Claude workflow，不把這些細節當成所有 CI/CD 場域的通用規則。&lt;/p>
&lt;h2 id="專案定位">專案定位&lt;/h2>
&lt;p>本專案的部署產物是靜態網站。Hugo 負責產生 HTML，Pagefind 負責產生搜尋索引，GitHub Pages 負責 hosting，Playwright 負責驗證搜尋與版面行為。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>文件&lt;/th>
 &lt;th>責任&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;a href="github-actions-workflows/">GitHub Actions workflow&lt;/a>&lt;/td>
 &lt;td>記錄本專案 &lt;code>.github/workflows/&lt;/code> 的實際設定&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="與通用-cicd-的關係">與通用 CI/CD 的關係&lt;/h2>
&lt;p>本資料夾是實例層。通用 gate 原理、不同部署場域差異與失敗處理流程放在上層文章；本資料夾只回答「這個 blog 專案現在怎麼部署、失敗時要看哪裡」。術語定義統一回連 &lt;a href="https://tarrragon.github.io/blog/ci/knowledge-cards/" data-link-title="Knowledge Cards" data-link-desc="用原子化卡片整理 CI/CD 章節的核心術語，讓流程文章專注在判讀與決策">CI 知識卡片&lt;/a>。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>本專案 workflow：讀 &lt;a href="github-actions-workflows/">GitHub Actions workflow&lt;/a>。&lt;/li>
&lt;li>前端部署通用注意事項：讀 &lt;a href="../frontend-deploy/">前端部署 CI/CD&lt;/a>。&lt;/li>
&lt;li>CI gate 原理：讀 &lt;a href="../ci-gate-workflow-boundary/">CI gate 與 workflow 邊界&lt;/a>。&lt;/li>
&lt;li>Markdown CI 規則：讀 &lt;a href="https://tarrragon.github.io/blog/posts/blog-markdown-%E5%AF%AB%E4%BD%9C%E8%A6%8F%E7%AF%84%E8%88%87-mdtools-%E6%AA%A2%E6%9F%A5/" data-link-title="Blog Markdown 寫作規範與 mdtools 檢查" data-link-desc="本 blog 的 Markdown 排版規範權威契約。涵蓋 H1 禁用、MD024 siblings_only、反釣魚 TLD 校驗、卡片雙向完整性、front matter schema；改規則時要與 scripts/mdtools 實作同步。">Blog Markdown 寫作規範與 mdtools 檢查&lt;/a>。&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>本 blog 專案部署是前端靜態站部署的一個具體案例。這個資料夾只記錄本專案實際使用的 Hugo、Pagefind、Playwright、GitHub Pages 與 Claude workflow，不把這些細節當成所有 CI/CD 場域的通用規則。</p>
<h2 id="專案定位">專案定位</h2>
<p>本專案的部署產物是靜態網站。Hugo 負責產生 HTML，Pagefind 負責產生搜尋索引，GitHub Pages 負責 hosting，Playwright 負責驗證搜尋與版面行為。</p>
<table>
  <thead>
      <tr>
          <th>文件</th>
          <th>責任</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="github-actions-workflows/">GitHub Actions workflow</a></td>
          <td>記錄本專案 <code>.github/workflows/</code> 的實際設定</td>
      </tr>
  </tbody>
</table>
<h2 id="與通用-cicd-的關係">與通用 CI/CD 的關係</h2>
<p>本資料夾是實例層。通用 gate 原理、不同部署場域差異與失敗處理流程放在上層文章；本資料夾只回答「這個 blog 專案現在怎麼部署、失敗時要看哪裡」。術語定義統一回連 <a href="/blog/ci/knowledge-cards/" data-link-title="Knowledge Cards" data-link-desc="用原子化卡片整理 CI/CD 章節的核心術語，讓流程文章專注在判讀與決策">CI 知識卡片</a>。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>本專案 workflow：讀 <a href="github-actions-workflows/">GitHub Actions workflow</a>。</li>
<li>前端部署通用注意事項：讀 <a href="../frontend-deploy/">前端部署 CI/CD</a>。</li>
<li>CI gate 原理：讀 <a href="../ci-gate-workflow-boundary/">CI gate 與 workflow 邊界</a>。</li>
<li>Markdown CI 規則：讀 <a href="/blog/posts/blog-markdown-%E5%AF%AB%E4%BD%9C%E8%A6%8F%E7%AF%84%E8%88%87-mdtools-%E6%AA%A2%E6%9F%A5/" data-link-title="Blog Markdown 寫作規範與 mdtools 檢查" data-link-desc="本 blog 的 Markdown 排版規範權威契約。涵蓋 H1 禁用、MD024 siblings_only、反釣魚 TLD 校驗、卡片雙向完整性、front matter schema；改規則時要與 scripts/mdtools 實作同步。">Blog Markdown 寫作規範與 mdtools 檢查</a>。</li>
</ul>
]]></content:encoded></item></channel></rss>