2
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?

スケジュール実行で実現 - Qiita記事の予約投稿システム(第3回:予約投稿編)

2
Posted at

スケジュール実行で実現 - Qiita記事の予約投稿システム(第3回:予約投稿編)

⚠️ 注意事項

免責事項:

  • この記事の内容は 2025-12-30 時点の情報に基づいています
  • GitHub Actionsの仕様は変更される可能性があります
  • cron式のタイムゾーンはUTCです(JSTとの時差に注意)
  • 予約投稿の動作を事前にテストしてください

📝 TL;DR

  • 課題: 記事を書き溜めても、毎回手動で投稿するのが面倒
  • 解決策: GitHub ActionsのScheduled Workflowで予約投稿を実現
  • 効果: 週次投稿を完全自動化(手動作業0分)
  • 導入工数: 約 3時間

📊 改善効果サマリー

項目 改善前 改善後 削減率
週次投稿作業時間 10分 0分 100%削減
投稿忘れリスク なし 100%削減
導入コスト - 3時間 -
学習コスト - -

🎯 背景

なぜこの改善に取り組んだか

第1回でGitHub Actionsによる手動投稿、第2回でIFTTT連携によるX(Twitter)自動投稿を実現しましたが、まだ投稿タイミングは手動でした。

  • 記事を書き溜めても、投稿は手動で行う必要がある
  • 「今週はまだ投稿していない」と思い出す必要がある
  • 最適な投稿タイミング(日曜朝など)に投稿したい
  • 記事を事前に準備して、スケジュール通りに投稿したい

対象読者

  • Qiita記事を定期的に投稿したい方
  • GitHub Actionsのcron式を学びたい方
  • 予約投稿機能を実装したい方
  • ブログの運用を自動化したい方

😓 課題

画像

qiita-workflow-comparison-horizontal.png

従来の業務フロー

1. 記事を執筆(平日に書き溜め)
2. 投稿タイミングを思い出す(週末)
3. GitHub Actionsで手動実行(1分)
4. 投稿確認(1分)

合計: 約2分/記事(投稿タイミングを逃すリスクあり)

具体的な問題点

  1. 投稿忘れのリスク

    • 詳細: 投稿タイミングを思い出す必要がある
    • 影響: 週次投稿の習慣が崩れる
    • 頻度: 月1回程度発生
  2. 最適な投稿タイミングに投稿できない

    • 詳細: 日曜朝6:00に投稿したいが、手動では難しい
    • 影響: 読まれる可能性が下がる
  3. 記事の書き溜めができない

    • 詳細: 投稿日に記事を準備する必要がある
    • 影響: 計画的な記事執筆ができない

定量的な影響

- 投稿忘れリスク: 月1回 × 12ヶ月 = 年12回
- 投稿タイミングのずれ: 毎回

→ 定期投稿の習慣が崩れるリスク

💡 解決策

採用したアプローチ

GitHub ActionsのScheduled Workflowとファイル名ベースの予約投稿システムを構築しました。

仕組み:

  1. 記事ファイル名に公開日を含める(例: 2025-12-31-記事タイトル.md
  2. GitHub Actionsが毎週日曜6:00に自動実行
  3. 公開日が今日以前の記事を自動的に private: false に変更
  4. 変更をコミット & プッシュ → Qiitaに自動投稿

選定理由:

  • ✅ 完全自動化(手動作業0)
  • ✅ ファイル名で予約日を管理(シンプル)
  • ✅ GitHub Actionsの無料枠で十分
  • ✅ いつでも手動実行可能

代替案との比較:

項目 GitHub Actions Qiita予約投稿 WordPress予約投稿
導入コスト 中(3時間) なし 高(WordPress必要)
カスタマイズ性
Gitでの管理 可能 不可 不可
料金 無料 なし(機能なし) 有料プランが多い

改善後の業務フロー

1. 記事を執筆(平日に書き溜め)
2. ファイル名に公開日を設定(例: 2025-12-31-記事タイトル.md)
3. Gitにコミット & プッシュ
4. 毎週日曜6:00に自動チェック & 自動投稿

合計: 約0分/記事(完全自動化)

アーキテクチャ図

image.png

🔧 実装

開発環境

項目 詳細
OS Windows 11
Git 2.43.0
GitHub Actions ubuntu-latest
シェル Bash

セットアップ手順

1. Scheduled Publishワークフローの作成

.github/workflows/weekly-scheduled-publish.yml を作成します。

name: Weekly Scheduled Publish (毎週日曜 6:00)

# 毎週日曜日 6:00 JST(土曜日 21:00 UTC)に実行
# 2026-01-03 から有効化

on:
  # 毎週日曜日 6:00 JST(土曜日 21:00 UTC)に実行
  schedule:
    - cron: '0 21 * * 6'  # 土曜 21:00 UTC = 日曜 6:00 JST
  # 手動実行も可能
  workflow_dispatch:

permissions:
  contents: write

jobs:
  update-publish-status:
    runs-on: ubuntu-latest

    steps:
      - name: 📅 有効化日をチェック
        id: activation_check
        run: |
          TODAY=$(date -u +%Y-%m-%d)
          echo "Today: $TODAY"

          # 有効化日: 2026-01-03
          if [[ "$TODAY" < "2026-01-03" ]]; then
            echo "⚠️ このワークフローは 2026-01-03 から有効化されます"
            echo "SKIP=true" >> $GITHUB_OUTPUT
            exit 0
          fi

          echo "✅ ワークフロー有効化済み"
          echo "SKIP=false" >> $GITHUB_OUTPUT

      - name: Checkout repository
        if: steps.activation_check.outputs.SKIP != 'true'
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Update article publish status
        if: steps.activation_check.outputs.SKIP != 'true'
        id: update
        run: |
          set -euo pipefail
          shopt -s nullglob

          CHANGED=0
          TODAY=$(date -u +%Y-%m-%d)

          echo "## 📝 Weekly Scheduled Publish - $TODAY" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "📅 Today: $TODAY" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY

          # qiita/public/ 配下のMarkdownファイルを処理
          for file in qiita/public/*.md; do
            if [ ! -f "$file" ]; then
              continue
            fi

            # ファイル名から日付を抽出(YYYY-MM-DD形式)
            filename=$(basename "$file")
            if [[ $filename =~ ^([0-9]{4}-[0-9]{2}-[0-9]{2})- ]]; then
              publish_date="${BASH_REMATCH[1]}"

              echo "📝 Processing: $filename" >> $GITHUB_STEP_SUMMARY
              echo "   Publish date: $publish_date" >> $GITHUB_STEP_SUMMARY

              # 公開日が今日以前かチェック
              if [[ "$publish_date" < "$TODAY" ]] || [[ "$publish_date" == "$TODAY" ]]; then
                # private: true を private: false に変更
                if grep -q "^private: true" "$file"; then
                  sed -i 's/^private: true/private: false/' "$file"
                  echo "   ✅ Changed to public" >> $GITHUB_STEP_SUMMARY
                  CHANGED=1
                else
                  echo "   ℹ️  Already public or no private field" >> $GITHUB_STEP_SUMMARY
                fi
              else
                echo "   ⏰ Not yet (publish date: $publish_date)" >> $GITHUB_STEP_SUMMARY
              fi
              echo "" >> $GITHUB_STEP_SUMMARY
            fi
          done

          echo "CHANGED=$CHANGED" >> $GITHUB_OUTPUT

          echo "---" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          if [ $CHANGED -eq 1 ]; then
            echo "✅ **Some articles were updated to public status**" >> $GITHUB_STEP_SUMMARY
          else
            echo "ℹ️ **No articles to update**" >> $GITHUB_STEP_SUMMARY
          fi

      - name: Commit and push if changed
        if: steps.activation_check.outputs.SKIP != 'true' && steps.update.outputs.CHANGED == '1'
        run: |
          git config --local user.email "github-actions[bot]@users.noreply.github.com"
          git config --local user.name "github-actions[bot]"
          git add qiita/public/*.md
          git commit -m "🗓️ Auto-update article publish status [skip ci]"
          git push

2. Publish Articlesワークフローの更新

workflow_run トリガーを追加して、Scheduled Publish完了後に自動実行されるようにします。

on:
  push:
    branches:
      - main
    paths:
      - 'qiita/public/**'
  # Scheduled Publishワークフロー完了後に自動実行
  workflow_run:
    workflows: ["Weekly Scheduled Publish (毎週日曜 6:00)"]
    types:
      - completed
  workflow_dispatch:

実装詳細

ステップ1: cron式の理解

GitHub Actionsのcron式はUTCで動作します。

# cron式の形式
# ┌───────────── 分 (0 - 59)
# │ ┌───────────── 時 (0 - 23)
# │ │ ┌───────────── 日 (1 - 31)
# │ │ │ ┌───────────── 月 (1 - 12)
# │ │ │ │ ┌───────────── 曜日 (0 - 6) (日曜=0, 月曜=1, ..., 土曜=6)
# │ │ │ │ │
# * * * * *

# 例: 毎週日曜 6:00 JST = 土曜 21:00 UTC
'0 21 * * 6'  # 土曜 21:00 UTC

ポイント:

  • UTCとJSTの時差は9時間
  • 日曜 6:00 JST = 土曜 21:00 UTC
  • 曜日は0(日曜)〜6(土曜)

ステップ2: ファイル名から日付を抽出

Bash正規表現でファイル名から日付を抽出します。

filename="2025-12-31-記事タイトル.md"

# 正規表現で日付を抽出
if [[ $filename =~ ^([0-9]{4}-[0-9]{2}-[0-9]{2})- ]]; then
  publish_date="${BASH_REMATCH[1]}"  # 2025-12-31
  echo "Publish date: $publish_date"
fi

ポイント:

  • ^([0-9]{4}-[0-9]{2}-[0-9]{2})- で YYYY-MM-DD 形式を抽出
  • BASH_REMATCH[1] で最初のキャプチャグループを取得

注意点:

  • ファイル名は必ず YYYY-MM-DD- で始める必要がある
  • 日付形式が間違っていると無視される

ステップ3: private: true を private: false に変更

sed コマンドでフロントマターを更新します。

# private: true を private: false に変更
sed -i 's/^private: true/private: false/' "$file"

# 確認
if grep -q "^private: true" "$file"; then
  echo "Still private"
else
  echo "Changed to public"
fi

ポイント:

  • -i オプションでファイルを直接編集
  • ^private: true で行頭の private: true のみマッチ

ステップ4: workflow_run でワークフロー連鎖

Scheduled Publish完了後にPublish Articlesを自動実行します。

workflow_run:
  workflows: ["Weekly Scheduled Publish (毎週日曜 6:00)"]
  types:
    - completed

ポイント:

  • workflows にはワークフロー名を指定
  • types: completed で成功/失敗に関わらず実行
  • 成功時のみ実行したい場合は、条件分岐を追加
if: ${{ github.event.workflow_run.conclusion == 'success' }}

📈 効果測定

定量的な効果

作業時間の削減

作業 改善前 改善後 削減時間
投稿タイミングを思い出す 1分 0分 1分
GitHub Actionsで手動実行 1分 0分 1分
投稿確認 1分 0分 1分
合計 3分 0分 3分 (100%削減)

年間削減効果の試算

1回あたりの削減時間: 3分
月間投稿回数: 4回
年間投稿回数: 4回 × 12ヶ月 = 48回

年間削減時間: 48回 × 3分 = 144分
               = 約 2.4時間の工数削減

※ 投稿忘れリスクもゼロに

定性的な効果

  • 完全自動化

    • 週次投稿が完全に自動化された
  • 投稿忘れリスクがゼロ

    • スケジュール通りに必ず投稿される
  • 最適な投稿タイミング

    • 日曜朝6:00という最適なタイミングで投稿
  • 記事の書き溜めが可能

    • 事前に記事を準備して、計画的に投稿できる
  • 心理的負担の軽減

    • 「投稿しなきゃ」というプレッシャーがなくなった

🚀 導入方法

導入の流れ

  1. 準備フェーズ(30分)

    • cron式の学習
    • タイムゾーン(UTC/JST)の理解
    • ファイル命名規則の決定
  2. 実装フェーズ(2時間)

    • Scheduled Publishワークフローの作成
    • Publish Articlesワークフローの更新
    • テスト記事の作成
  3. 検証フェーズ(30分)

    • 手動実行でテスト
    • ログの確認
    • 3日間のテスト運用

必要なリソース

人的リソース

  • エンジニア: GitHub Actions、Bash、cron式の知識

技術リソース

  • GitHub: 無料プラン(Actionsの無料枠)
  • Git: バージョン管理

時間リソース

  • 初期導入: 約 3時間
  • 学習期間: 約 2時間(cron式、Bash)
  • メンテナンス: 月1回(10分程度)

⚠️ 留意点・制約事項

技術的な制約

  1. cron式の実行タイミング

    • 内容: GitHub Actionsのcronは数分遅れる場合がある
    • 対策: 余裕を持ったスケジュール設定
  2. UTCとJSTの時差

    • 内容: cron式はUTCで動作(JSTとの時差9時間)
    • 対策: 時差計算を間違えないように注意
  3. ファイル名の命名規則

    • 内容: YYYY-MM-DD- で始める必要がある
    • 対策: テンプレートファイルを用意

運用上の注意点

  • 手動実行でテスト: 本番運用前に必ずテスト
  • ログの確認: GitHub ActionsのSummaryでログを確認
  • 緊急時の対応: ワークフローを一時停止可能

想定されるリスクと対策

リスク 影響度 発生確率 対策
cron実行の遅延 余裕を持ったスケジュール
時差計算ミス テスト運用で確認
ファイル名ミス テンプレート使用

こんな場合は不向き

  • ❌ 毎日投稿したい(cron式で対応可能だが、記事の準備が大変)
  • ❌ 投稿タイミングを柔軟に変えたい(手動実行で対応可能)
  • ❌ 記事数が少ない(手動投稿で十分)

🔄 今後の展開

短期的な改善計画(1〜3ヶ月)

  • 投稿前の自動プレビュー生成
  • 投稿後の自動通知(Slack、Discord)
  • 投稿統計の自動集計

中長期的な構想(6ヶ月〜1年)

  • AIによる記事の自動校正
  • SEO最適化の自動チェック
  • 画像の自動最適化

💬 まとめ

この改善で実現できたこと

  • ✅ 週次投稿を完全自動化(手動作業0分)
  • ✅ 投稿忘れリスクをゼロに
  • ✅ 記事の書き溜めが可能に

学んだこと・気づき

  1. cron式は強力

    • 定期実行で様々な自動化が可能
    • UTCとJSTの時差に注意
  2. ファイル名ベースの管理はシンプル

    • データベース不要
    • Gitで管理が完結
  3. ワークフロー連鎖で複雑な処理も可能

    • workflow_run で連鎖実行
    • 段階的な自動化が実現

推奨する人

  • ✅ Qiita記事を定期的に投稿したい方
  • ✅ 記事を書き溜めたい方
  • ✅ GitHub Actionsで自動化したい方

最後に

3回シリーズで、Qiita記事の投稿を完全自動化しました。

  • 第1回: GitHub Actionsで手動投稿
  • 第2回: IFTTT連携でX(Twitter)自動投稿
  • 第3回: スケジュール実行で予約投稿

これで、記事執筆に集中でき、投稿は完全に自動化されました。

補足:
予約投稿の動作を事前にテストしてください。特に、cron式のタイムゾーン(UTC/JST)に注意してください。

📚 参考資料

公式ドキュメント

関連記事


📝 更新履歴

  • 2025-12-30: 初版公開

タグ: #GitHub #GitHubActions #Qiita #自動化 #cron

2
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
2
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?