1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GitHub Actionsで個人開発メディアを毎日自動更新する仕組みを作った話【Next.js + Supabase + Gemini API】

1
Posted at

はじめに

「毎日手動で更新し続けるのは無理だ」

海外テックメディアを日本語で届けるサービスを作ろうと決めたとき、一番最初にぶつかった壁がこれでした。

毎朝RSSを手動で確認して、AIに貼り付けて、翻訳して、サイトに投稿する。これを毎日やるのは現実的じゃない。

そこで構築したのが、GitHub Actionsで全自動化されたパイプラインです。

朝起きたら新しい記事が承認待ちになっている。それだけを確認して承認ボタンを押せばいい。そういう状態を作ることが目標でした。

この記事では、その仕組みと、構築中にハマったポイントを紹介します。


作ったもの

Mirai Signal — 海外AI・ロボティクス・半導体などの最先端技術情報を毎日自動収集・日本語化して届けるメディアです。

技術スタックはこちら。

  • フロントエンド:Next.js(App Router)+ TypeScript
  • データベース:Supabase
  • AI処理:Gemini API(gemini-2.5-flash-lite)
  • メール配信:Resend
  • デプロイ:Vercel
  • 自動化:GitHub Actions(←この記事のメインテーマ)

パイプラインの全体像

毎朝JST 7:00 に以下が自動で動きます。

GitHub Actions(毎朝7時に起動)
↓
save-articles.ts(RSS収集)
↓
process-articles.ts(Gemini APIでスコアリング・翻訳)
↓
send-newsletter.ts(ニュースレター配信)
↓
管理画面で手動承認
↓
サイトに公開

GitHub Actionsの設定

実際のワークフローファイルがこちらです。

name: Daily Pipeline
on:
  schedule:
    - cron: '0 22 * * *'  # UTC 22:00 = JST 7:00
  workflow_dispatch:       # 手動実行も可能
jobs:
  pipeline:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - name: Install dependencies
        run: npm ci
      - name: Run pipeline
        env:
          SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
          SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}
          GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
          RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}
        run: |
          npx tsx scripts/save-articles.ts
          npx tsx scripts/process-articles.ts
          npx tsx scripts/send-newsletter.ts

シンプルに見えますが、ここにたどり着くまでにかなりハマりました。

ポイント:cronの書き方

GitHub ActionsのスケジュールはUTC基準です。JST 7:00に実行したい場合は'0 22 * * *'と書きます(JSTはUTC+9なので、7-9=-2、つまり前日の22:00)。

ポイント:環境変数の渡し方

APIキーなどの秘密情報はGitHub SecretsにセットしておいてYAMLで参照します。${{ secrets.変数名 }}という形式で使えます。

セットの手順:

  1. GitHubのリポジトリページを開く
  2. Settings → Secrets and variables → Actions
  3. 「New repository secret」から追加

ポイント:TypeScriptスクリプトの実行

npx tsxを使うとTypeScriptのスクリプトをコンパイルなしで直接実行できます。Node.jsプロジェクトなのでnpm ciで依存パッケージをインストールしてから実行します。


ハマったポイント4選

1. YAMLの構文エラーが見えないところにあった

一番長く詰まったのがこれです。

PowerShellでYAMLファイルを直接編集したところ、見えない文字や改行コード(CRLF)の問題が混入してしまいました。特にrun: |のブロック内で起きやすく、何日もワークフローが失敗し続けました。

解決策:YAMLファイルを直接編集するのをやめて、Node.jsスクリプトでファイルを書き出す方式に切り替えました。PowerShellは日本語や特殊文字の扱いが独特で、ファイルを直接触ると文字化けや改行コードの問題が起きやすいです。

// write-workflow.js
const fs = require('fs');
const yaml = `name: Daily Pipeline
on:
  schedule:
    - cron: '0 22 * * *'
...`;
fs.writeFileSync('.github/workflows/daily-pipeline.yml', yaml, 'utf8');

2. 環境変数を設定したのに渡っていなかった

GitHub SecretsにAPIキーを登録したのに、スクリプトが「Missing API key」エラーで落ちる。原因が全然分からず数日悩みました。

原因はシンプルで、YAMLのenv:セクションに記載するのを忘れていただけでした。

# NG:envセクションにRESEND_API_KEYがない
env:
  SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
  GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
  # RESEND_API_KEY を書き忘れ!

# OK:全部ちゃんと書く
env:
  SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
  SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}
  GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
  RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }}

GitHub SecretsはあくまでGitHubが管理している変数で、YAMLでenv:に書いて初めてスクリプトから参照できます。登録しただけでは使えません。

3. pushトリガーと勘違いしていた

コードをpushするたびにActionsのページに新しい実行ログが表示されるので、「あれ、スケジュール実行されているのかな?」と思っていました。

でも実態は違いました。表示されていたのはスケジュール実行の失敗ログで、pushによって実行されていたわけではありませんでした。

GitHubのActionsタブでは、失敗したワークフローは赤いアイコンで残り続けます。新しく何かが動いたように見えても、それが何のトリガーで動いたのかをちゃんと確認することが重要です。

4. 「Re-run failed jobs」では直らなかった

ワークフローファイルを修正してpushした後、失敗していた古いワークフローのページにある「Re-run failed jobs」ボタンを押していました。でも何度やっても同じエラーになる。

原因は、「Re-run failed jobs」は修正前の古いワークフローファイルで再実行するからです。ワークフローファイルを変更した場合、新しいpushで実行されたワークフローを確認する必要があります。


実際に動かしてみた結果

構築から約1ヶ月、毎日安定して動き続けています。

  • 毎朝7時に自動で起動
  • 12ソースのRSSから記事を収集
  • Gemini APIでスコアリング・翻訳
  • 承認待ち記事が管理画面に並ぶ

朝起きて管理画面を開くと、前日夜から集まった記事が並んでいます。それを確認して承認するだけ。運営にかかる時間は1日数分になりました。

GitHub Actionsのログ画面で実行状況もリアルタイムで確認できるので、何か問題が起きたときもすぐ気づけます。


まとめ

GitHub Actionsで自動化したことで、手動で毎日更新するという無理ゲーが現実的な運営に変わりました。

ハマったポイントをまとめると:

  • PowerShellで直接YAMLを編集すると改行コード問題が起きやすい → Node.jsスクリプト経由で書き出す
  • GitHub Secretsに登録するだけでは不十分 → YAMLのenv:セクションにも書く
  • Actionsのログはどのトリガーかをよく確認する
  • ワークフロー修正後は「Re-run failed jobs」ではなく新しいpushを確認する

個人開発でも自動化を入れると継続のハードルが一気に下がります。同じようなことをやろうとしている方の参考になれば嬉しいです。


前回の記事:

X(Twitter)でも毎日情報発信しています。→ @MqS_quest

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?