GitHub ActionsからGoogle Bloggerに完全自動ポストできるか検証する

結論から先に

Service Accountで認証する場合、Google Bloggerへポストする権限がなく、完全自動化はできない。

自動化しようとした背景

WordPressで運用していたブログをGoogle Bloggerにマイグレーションした際、 移行ツールはあるものの結構手間だった。特に画像の移行。 なので今後ブログサーバーの移行があっても楽できるように ブログのリソース(記事、画像)はGitHubで管理、ついでに諸々自動化できたらというのが動機。

やりたいこと

  • ブログのリソース(記事や画像)はGitHubで管理したい。
  • 記事はMarkdownで書きたい。
  • リポジトリにPushしたらGitHub ActionsでBloggerに自動で投稿したい。

事前準備

Google Blogger APIを利用するにあたり、認証に必要な設定をしておく。

Google Cloud設定

Google BloggerのアカウントでGoogle Cloudのプロジェクトは作成済みであることを前提とする。

Blogger APIの有効化

作成済みのGoogle Cloudのプロジェクトで、Blogger APIを有効する。 Google Cloud Consoleの[APIとサービス] > [ライブラリ]で[Blogger API]を検索。

有効にする。

Service Accountの作成

GitHub ActionsからBlogger APIにアクセスするために、サービスアカウントを作成。

Google Cloud Consoleの[IAMと管理] > [サービスアカウント]で、新しいサービスアカウントを作成。

キーの作成

サービスアカウントの認証に使用するJSON形式のキーを作成。 Google Cloud Consoleのサービスアカウントの詳細ページで、[鍵]タブを選択し、 [キーを追加] > [新しい鍵を作成]を選択。キーのタイプは[JSON]を選択し[作成]。 キーファイルがダウンロードされる。

GitHubリポジトリへのシークレット登録

作成したサービスアカウントキーの内容を、GitHubリポジトリのシークレットとして登録。 リポジトリの[Settings] > [Secrets and variables] > [Actions]で、[New repository secret]押下し、 [Name]と[Secret](サービスアカウントキーファイルの内容)を入力して保存。

GitHub Actionsのワークフロー作成

ざっくりとしたフロー

  1. mainブランチへのプッシュで起動
  2. Gitリポジトリをcheckout
  3. commitしたmdをhtmlへ変換
  4. Google Cloud認証
  5. htmlをGoogle BloggerへPost

md -> html変換

pandocを利用する。

GitHub Actions から Google Cloud への認証

google-github-actions/authでService Account Key Jsonでの認証を利用する。

実装内容

.github/workflows/insert-post-to-google-blogger.yaml

name: Insert post to Google Blogger

on:
  push:
    branches: 
    - main
    paths:
    - '**/*.md'
    - '.github/**/*.*'
  workflow_dispatch:

jobs:
  call-blogger-api:
    runs-on: ubuntu-latest
    permissions:
      contents: 'write'
    steps:
      - uses: actions/checkout@v4
        with: 
          fetch-depth: 2
      - uses: actions/setup-python@v5
        with:
          python-version: '3.13.1'
      - name: Convert Markdown to HTML
        env:
            GITHUB_EVENT_BEFORE: ${{ github.event.before }}
            GITHUB_EVENT_REPOSITORY_URL: ${{ github.event.repository.url}}
        run: |
          set -eux
          sudo apt-get install -y pandoc
          pip install --user pandoc-include

          diff_list=$(git diff --name-only ${GITHUB_EVENT_BEFORE}..HEAD)

          for file in $diff_list; do
            if [[ ${file} != *.md ]]; then
              continue
            fi
            
            dir_name=$(dirname ${file})
            html_dir=${dir_name}/html
            mkdir -p ${html_dir}

            # md -> html変換
            html_file=${html_dir}/$(basename "${file}" .md).html
            # pandoc -f markdown -t html "${file}" > ${html_file}
            pandoc -f markdown -t html --filter pandoc-include "${file}" > ${html_file}

            # img パス置換
            # https://github.com/d4y8/learning-labs/blob/main/blog-cicd/README-images
            # ↓
            # https://github.com/d4y8/learning-labs/blob/main/<MARKDOWN_DIR_PATH>/README-images

            before_path="\.\/README-images"

            after_path="${GITHUB_EVENT_REPOSITORY_URL}/blob/main/${dir_name}/README-images"
            after_path=${after_path//\//\\/}
            after_path=${after_path//./\\.}
            after_path=${after_path//\?/\\\?}

            sed -i 's/'${before_path}'/'${after_path}'/g' ${html_file}

            before_string="\.png\""
            after_string="\.png\?raw=true\""

            sed -i 's/'${before_string}'/'${after_string}'/g' ${html_file}

            cat ${html_file}
            echo ${html_file} >> html.txt
          done

          if [[ -n ${html_file} ]]; then
            git config user.name  "actions-user"
            git config user.email "action@github.com"
            git add **/*.html
            git commit -m "Converted Markdown to HTML"
            git push
          fi

      - name: Set up authentication
        uses: google-github-actions/auth@v2
        with:
          credentials_json: ${{ secrets.GOOGLE_CREDENTIALS }}

      - name: Install dependencies
        run: pip install google-api-python-client

      - name: Call Blogger API
        env: 
          BLOG_ID: ${{ secrets.BLOG_ID }}
        run: |
          python .github/scripts/blog_post.py

.github/scripts/blog_post.py

import os

from googleapiclient.discovery import build

service = build("blogger", "v3")

# ブログIDを指定
blog_id = os.environ.get("BLOG_ID")

with open("html.txt", "r", encoding="utf-8") as f:
    html_files = f.read().splitlines()

for filepath in html_files:
    print(filepath)
    try:
        with open(filepath, "r", encoding="utf-8") as file:
            html_content = file.read()

            body = {
                "content": html_content,
                "title": "test title"
            }

            # listは権限あり
            # results = service.posts().list(blogId=blog_id).execute()
            # print(results)

            # insertは403エラー
            result = service.posts().insert(blogId=blog_id, contents=body).execute()
            print(result)

    except UnicodeDecodeError:
        print(f"Error: Encoding error in {filepath}")
    except Exception as e:
        print(f"Error processing {filepath}: {e}")

GitHub Actionsが実行されると、Bloggerへの投稿時に403エラー

エラー内容

<HttpError 403 when requesting https://blogger.googleapis.com/v3/blogs/***/posts?alt=json returned "We're sorry, but you don't have permission to access this resource.". Details: "[***'message': "We're sorry, but you don't have permission to access this resource.", 'domain': 'global', 'reason': 'forbidden'***]">

原因

Service AccountではGoogle Bloggerに記事を投稿する権限はない。

対策(検討)

なし、、、HTMLファイルをリポジトリの保存して、それをGoogle Bloggerに手動更新する。

今後やれたら

Textlint、Google Search Console、SNSポスト辺りも自動化できたら良い。

Troubleshooting

その他、発生したエラーと対処。

git diff 実行時にエラー

GitHub Actionsのジョブにて以下のようにgit diffしたところエラーとなった。

git diff --name-only ${{ github.event.before }}..HEAD)
fatal: Invalid revision range ef1dd6de85606d4627addee932fd51ba7bff9e7d..HEAD
Error: Process completed with exit code 128.

原因

actions/checkoutのfetch-depthのデフォルトは1で、 その場合、最新の履歴のみフェッチされ一つ前の履歴はfetchされていないから。

https://github.com/actions/checkout?tab=readme-ov-file#usage

解決方法

fetch-depth2に変更

### GitHub Actionsでgit push

remote: Permission to d4y8/learning-labs.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/d4y8/learning-labs/': The requested URL returned error: 403

原因

ジョブがコンテンツへの書き込み権限を持っていないため。

解決方法

ジョブに書き込み権限を付与する。

jobs:
  call-blogger-api:
    runs-on: ubuntu-latest
    permissions:
      contents: 'write' #追加

リポジトリ内のすべてのワークフローに共通して設定する場合は以下でもOK。

[Settings] > [Actions] > [General] > [Workflow permissions] Read and write permissionsを選択して[Save]。

コメント

このブログの人気の投稿

イオンのセルフレジでAEON Pay[イオンペイ]を使ってWAONポイントを使う方法

WAONポイントの使い方、損していませんか?

楽天ペイのSuicaにチャージする時の認証を変更する