GitHub ActionsでZenn記事の予約投稿を実現する

公開:2020/11/23
更新:2020/11/23
3 min読了の目安(約3500字TECH技術記事

「Zenn で記事の予約投稿が出来ると便利だなー」と思って調べてたら GitHub Actions を使って実現できたので紹介します。

仕組み

予約投稿の仕組みは記事追加のプルリクエストの日時指定のマージです。
その実現のためにMerge Scheduleという GitHub Action を利用します。

動きとしては以下の通りです。

  1. ブランチを切り、公開したい記事を追加。プルリクエストを作成
  2. GitHub Actions が起動し、Merge Schedule が登録
  3. 日時指定でプルリクエストがマージされて master が更新
  4. Zenn で記事が公開

詳細

GitHub Actions の登録

Zenn の記事管理リポジトリに移動して GitHub Actions のディレクトリを作ります。

$ mkdir -p .github/workflows

次に workflows に以下merge-schedule.ymlを作成します。

name: Merge Schedule
on:
  pull_request:
    types:
      - opened
      - edited
      - synchronize
  schedule:
    - cron: 0 * * * *

jobs:
  merge_schedule:
    runs-on: ubuntu-latest
    steps:
      - uses: gr2m/merge-schedule-action@1ef6893192811edbec08113370a9d973922e84c7
        with:
          time_zone: "Asia/Tokyo"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

そして変更をコミット & プッシュします。
これでスケジュール投稿の準備が整いました。

上記コードではgr2m/merge-schedule-actioのバージョンをコミット指定にしています。このコミットは私が gr2m/merge-schedule-actio に送った Time Zone 対応の PR がマージされたときのコミットです。2020/11/23 時点で、このコミットが最新のリリースに取り込まれていないので、このような指定としています。
(この変更がないと UTC 標準時での時刻指定が必要になります)。
https://github.com/gr2m/merge-schedule-action/pull/29

プルリクエストの作成

ローカルでプルリクエスト作成用のブランチを切ります。

$ git checkout -b introduce-xvim2

このブランチ上で記事を作成します。記事ファイルの公開指定はpublished: trueとしてください。
作成が完了したらコミットしてプルリクエストを作成します。

$ git add introduce-xvim2.md
$ git commmit -m "feat: introduce-xvim2"
$ git push --set-upstream origin introduce-xvim2

そして、プルリクエスト 作成の際の Descriptions に以下のように ISO 形式で公開したい日時を入力してください。これがマージ実行日時(記事公開日時)となります。

/schedule 2020-11-21T20:00

この状態でプルリクエストをオープンし、起動されている GitHub Actions をみてみます。ワークフローが起動していますね。

詳細をみると先ほど指定した公開日時でスケジュールされているのがわかります。

あとは、その指定時間がくるとプルリクエストがマージされ記事が投稿されます。
便利!

注意点

merge-schedule の GitHub Actions がどのように動いているのかを確認したら、以下のようになっていました。

https://github.com/gr2m/merge-schedule-action/blob/master/lib/handle_schedule.js

注目するのは以下処理です。

const duePullRequests = pullRequests.filter(
  (pullRequest) => new Date(pullRequest.scheduledDate) < localeDate()
);

どうやら、cron での GitHub Actions 実行時点で、description 記載の実行日時を経過しているプルリクエストを抽出してマージ実行対象とするようです。

なので、厳密に Descriptions に記載した日時にマージされるのではなく、cron での CI 実行時間により左右されます。

もし分単位の公開指定をしたい場合は、GitHub Actions の cron の指定を変える必要があります。
サンプルの例だとcron: 0 * * * *で、1 時間に 1 回しか実行されません。
例え/schedule 2020-11-21T20:45と、20 時 45 分に実行を指定しても、それは2020-11-21T21:00前後に実行されます。

もし、ほぼ 45 分に実行して欲しい場合は merge-schedule.ymlの cron の指定を45 * * * *とするか、0/15 * * * *, * * * * *実行などに変更する必要があります。

ただ、このような指定とするとその分 GitHub Actions が実行されるので、 予約投稿日時によっては GitHub Actions の実行時間の無料枠を超過する可能性がある ことに注意してください。

現実的な設定は、予約投稿するであろう 11-12 時、 18-22 時に cron の起動を限定して
0 3,4,9-12 * * *とかにするのが良い
と思います(cron は UTC 日時なので、-9 時間で設定)。

おわりに

以上「GitHub Action で Zenn の予約投稿を実現する」でした。
こういう応用が効くのも Zenn の良さですね。

自分のライフサイクル的に朝に記事を書きあげることが多いので、予約投稿はとても欲しかった機能でした。来月からスタートするアドベントカレンダーでも使っていきたいです。