GitHub Actionsで記事サイトを自動検品する|失敗ならデプロイしない設計

Astroの記事サイトを例に、依存関係の固定、静的ビルド、Markdownの独自検算、失敗時の配信停止、同時実行の制御までをGitHub Actionsの設定例で解説します。

GitHub Actionsで依存関係の導入、Astroのビルド、記事独自の検算、デプロイを直列に並べ、失敗したら配信へ進ませない設計を作ります。自動化する作業の選び方は、毎日の繰り返し作業を自動化する考え方も参考になります。

配信前ゲートの全体像

配信前ゲートとは、公開してよい状態かを機械判定する関所です。次の順番を固定します。

  1. リポジトリの内容を取得する
  2. 指定したNode.jsを用意する
  3. lockfileどおりに依存パッケージを導入する
  4. Astroをビルドする
  5. 記事固有のルールを検算する
  6. すべて成功した場合だけデプロイする

ビルドはMarkdownやfrontmatter(記事冒頭のメタ情報)の型エラーを見つけます。文字数、見出し、出典などの編集ルールは独自検算で補います。記事作りを半自動化する手順のように、生成、検品、公開を分けると役割が明確です。

関所主なコマンド・設定失敗したとき
依存関係npm cilockfileの不一致や導入エラーで停止
静的ビルドnpm run buildAstroのビルドエラーで停止
記事検算npm run kensan独自ルール違反で停止
デプロイ前3段の後ろに配置前段が失敗した実行では開始しない
同時実行cancel-in-progress: true同じグループの古い実行をキャンセル

installとbuildを分ける

CI(変更ごとの自動検証)ではnpm ciを使います。既存のpackage-lock.jsonなどが必須で、package.jsonと不一致ならlockfileを更新せず失敗します。導入とビルドを別ステップにすれば、失敗箇所をログで判別できます。

name: 記事サイトの検品と配信

on:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read

jobs:
  verify-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: ソースを取得
        uses: actions/checkout@v7

      - name: Node.jsを準備
        uses: actions/setup-node@v7
        with:
          node-version: 24
          cache: npm

      - name: 依存関係を固定して導入
        run: npm ci

      - name: Astroをビルド
        run: npm run build

2026年7月23日の公式使用例は両Actionともv7です。メジャーバージョンは固定しつつ、更新時は各Actionのリリースノートとランナー要件を確認します。Node.jsもローカルと同じ版へ固定してください。setup-nodeのnpmキャッシュはパッケージ管理用データを再利用しますが、node_modules自体はキャッシュしません。詳しい使い分けはGitHub Actionsのキャッシュ入門で確認できます。

独自検算を追加する

独自検算は違反時に0以外の終了コードを返します。警告を表示するだけで正常終了してはいけません。たとえば次を確認します。

  • frontmatterに必須項目がある
  • H1を置かず、H2が一つ以上ある
  • 本文が最低文字数を満たす
  • 内部リンク先が存在する

違反理由とファイル名をerrorsへ追加します。

const errors = [];

// 各Markdownを検査し、違反があればerrorsへ追加する

if (errors.length > 0) {
  console.error(errors.join('\n'));
  process.exit(1);
}

console.log('記事検算に合格しました');

package.json"kensan": "node tools/kensan.mjs"を登録し、ワークフローから呼びます。

      - name: 記事ルールを検算
        run: npm run kensan

まず必須項目とリンク切れを失敗条件にし、表記揺れなどは警告に分けると段階導入できます。

失敗時に配信を止める

同じジョブのステップは上から実行され、条件式には既定でsuccess()が適用されます。検算の後ろへデプロイを置けば、前段が成功した場合だけ配信されます。

      - name: 記事ルールを検算
        run: npm run kensan

      - name: 本番へデプロイ
        run: npm run deploy

検算にcontinue-on-error: true、配信にif: always()は付けません。前者は失敗を許容し、後者は前段の結果にかかわらず実行させるためです。

別ジョブへ分けるなら配信側にneeds: verifyを指定します。依存先が失敗すると配信側も通常はスキップされます。ただし別ジョブへdistを渡す処理が増えるため、小規模サイトは同一ジョブから始めると追いやすくなります。停止時は最後に成功したステップと終了コードを見ます。自動化の失敗を切り分ける基本も確認表になります。

同時実行を制御する

短時間に複数回pushすると、古い配信が後から完了する可能性があります。concurrencyで同じグループの実行を制御します。

concurrency:
  group: article-deploy-${{ github.ref }}
  cancel-in-progress: true

この例はブランチごとに古い実行をキャンセルします。同じグループの実行順は保証されないため、順番待ちではなく古い配信を残さない用途に使います。

ローカルとCIの差を減らす

CIだけ失敗するときは、コマンド、Node.js、環境変数の差を疑います。

  1. ローカルでも同じ3コマンドを同じ順序で実行する
  2. Node.jsの版を合わせる
  3. 検算をリポジトリ内のスクリプトにする
  4. 配信の秘密はデプロイだけで参照する

共通入口なら、人とActionsが同じ処理を再現できます。最初は検品だけ動かし、安定後にデプロイを加える方法もあります。

導入後の確認項目

最初から多くの規則を必須にすると、原因の切り分けが難しくなります。次の順で導入すると、どの関所が効いたかを確認しやすくなります。

  1. pull requestでnpm cinpm run buildnpm run kensanを動かす
  2. 意図的に検算違反を1件作り、ジョブが0以外の終了コードで失敗することを確かめる
  3. mainへのデプロイを後段へ追加し、検算失敗時に実行されないことを確かめる
  4. 短時間に2回更新し、古い実行がキャンセルされることを確かめる

ジョブが長引く場合はGitHub Actionsにタイムアウトを追加する方法を、通知まで整える場合はGitHub Actionsの失敗通知を次の手順にできます。

よくある質問

npm installではなくnpm ciを使う理由は何ですか?

npm ciは既存のlockfileを前提にし、package.jsonと内容が合わなければ更新せず終了します。開発者ごとの差を減らし、CIで同じ依存関係を再現したい場合に向いています。

Astroのビルドだけで記事検品は十分ですか?

十分とは限りません。astro buildは配信用ファイルを生成する工程ですが、最低文字数や出典数、独自の見出し規則まで自動で保証するものではありません。サイト固有の編集基準は別の検算スクリプトで補います。

検算だけ失敗してもデプロイを続けられますか?

設定上は可能ですが、配信前ゲートの目的とは合いません。検算ステップへcontinue-on-error: trueを付けず、デプロイを同じジョブの後段に置くか、needsで検品ジョブへ依存させます。

キャッシュを使うとnpm ciは不要になりますか?

不要にはなりません。キャッシュはパッケージ取得を速めるための仕組みで、依存関係をlockfileどおりに導入する処理の代わりではありません。キャッシュが見つからない場合も動く構成にします。

一次情報の確認メモ

確認日: 2026-07-23

続き(結論と実データ)はnoteに置いています

ここでは手順のところまで書きました。実際に出た数字、うまくいかなかった条件、そのまま使える設定ファイルは、 note の記事にまとめてあります。

noteで続きを読む Xをフォローする