Zenn記事をXに自動投稿するGitHub Actions設定手順
Zennで記事を公開したら、手動でXにシェアしていませんか?
「記事を書き終えた達成感で満足してしまい、Xへの投稿を忘れる」「毎回URLをコピペするのが地味に面倒」——そんな経験があるなら、GitHub Actionsで自動化してしまうのがおすすめです。
一度設定すれば、Zennへのpushをトリガーにして、自動でXに投稿が流れるようになります。
仕組みをざっくり理解する
この自動化は、3つの要素を組み合わせています。
- Zenn + GitHub連携:記事をGitHubリポジトリで管理し、pushすると自動で公開される
- GitHub Actions:pushや定期実行をトリガーに処理を走らせる
- X API:プログラムからXに投稿する
流れとしては「GitHubにpush → Actionsが起動 → X APIで投稿」というシンプルな構成です。
事前に必要なもの
Zenn側の準備
ZennとGitHubリポジトリを連携済みであることが前提です。まだの場合は、Zenn公式の「Zenn CLIで記事・本を管理する方法」を参考に設定してください。
記事はarticles/ディレクトリにMarkdownファイルとして配置し、Front Matterでpublished: trueにすると公開対象になります。
---
title: "記事タイトル"
emoji: "📝"
type: "tech"
topics: ["github", "automation"]
published: true
---
X API側の準備
X(旧Twitter)APIを使うには、開発者アカウントとアプリの登録が必要です。
- X Developer Portalでアプリを作成
- OAuth 1.0aのアクセストークンを取得(API Key、API Secret、Access Token、Access Token Secretの4つ)
この4つの値は、後でGitHub Secretsに登録します。
GitHub Actionsのワークフロー設定
リポジトリに.github/workflows/post-to-x.ymlを作成します。
name: Post to X
on:
push:
branches:
- main
paths:
- 'articles/*.md'
jobs:
post:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Get changed files
id: changed
run: |
CHANGED=$(git diff --name-only HEAD~1 HEAD -- 'articles/*.md' | head -1)
echo "file=$CHANGED" >> $GITHUB_OUTPUT
- name: Extract article info
if: steps.changed.outputs.file != ''
id: article
run: |
FILE="${{ steps.changed.outputs.file }}"
SLUG=$(basename "$FILE" .md)
TITLE=$(grep -m1 '^title:' "$FILE" | sed 's/title: *"\(.*\)"/\1/')
echo "slug=$SLUG" >> $GITHUB_OUTPUT
echo "title=$TITLE" >> $GITHUB_OUTPUT
- name: Post to X
if: steps.article.outputs.slug != ''
env:
API_KEY: ${{ secrets.X_API_KEY }}
API_SECRET: ${{ secrets.X_API_SECRET }}
ACCESS_TOKEN: ${{ secrets.X_ACCESS_TOKEN }}
ACCESS_TOKEN_SECRET: ${{ secrets.X_ACCESS_TOKEN_SECRET }}
run: |
TWEET_TEXT="${{ steps.article.outputs.title }} を公開しました!
https://zenn.dev/あなたのユーザー名/articles/${{ steps.article.outputs.slug }}"
# ここでX APIを呼び出す(実際にはOAuth署名が必要)
echo "投稿内容: $TWEET_TEXT"
GitHub Secretsの登録
リポジトリの「Settings → Secrets and variables → Actions」から、以下の4つを登録します。
X_API_KEYX_API_SECRETX_ACCESS_TOKENX_ACCESS_TOKEN_SECRET
Secretsに保存した値はログに出力されないため、安全に管理できます。
実装時のポイント
X APIの認証について
上記のサンプルは構造を示すための簡略版です。実際にX APIへ投稿するには、OAuth 1.0aの署名付きリクエストを送る必要があります。
Node.jsならtwitter-api-v2、Pythonならtweepyなどのライブラリを使うと、署名処理を任せられて楽です。
// Node.jsの例(twitter-api-v2使用)
const { TwitterApi } = require('twitter-api-v2');
const client = new TwitterApi({
appKey: process.env.API_KEY,
appSecret: process.env.API_SECRET,
accessToken: process.env.ACCESS_TOKEN,
accessSecret: process.env.ACCESS_TOKEN_SECRET,
});
await client.v2.tweet('記事を公開しました! https://zenn.dev/...');
scheduleトリガーを使う場合の注意
pushではなく定期実行(on: schedule)で動かす場合、いくつか知っておくべき点があります。
- cronはUTC指定。日本時間の午前9時に実行したいなら
0 0 * * *(UTC 0時 = JST 9時) - 毎時0分は混雑しやすく、遅延やスキップが起きることがある。5分や15分にずらすのが無難
- 公開リポジトリで60日間アクティビティがないと、scheduleが自動で無効化される
on:
schedule:
- cron: '15 0 * * *' # 毎日JST 9:15に実行
Zennのデプロイがスキップされるケース
コミットメッセージに[ci skip]や[skip ci]が含まれていると、Zenn側のデプロイが走りません。自動コミットを組み込む場合は、このキーワードを避けるようにしてください。
うまく動かないときのチェックリスト
- X APIのアクセストークンは「Read and Write」権限になっているか
- GitHub Secretsの名前にタイポはないか
-
pathsフィルタで対象ファイルが正しく指定されているか - ZennのユーザーURLは正しいか
Actionsの実行ログは「Actions」タブから確認できます。エラーが出ていれば、そこにヒントがあるはずです。
設定は最初だけ少し手間ですが、一度動き始めると「記事を書いてpushするだけ」で告知まで完了します。
記事を書くこと自体に集中できるようになるので、ぜひ試してみてください。