無料でプライベートリポジトリを使用してGitHub Pagesを公開する

✍🏼 作成日 2020年10月31日   
❗️ 注意:この記事が作成されてから既に 日が経過しています。情報の鮮度にご注意ください

はじめに

最近、Github PagesとGithub Actionsを組み合わせて使う方法を調べてみたところ、個人ブログのシナリオに非常に適していると感じたため、この記事を書くことにしました。

私のブログは以前、ソースコードを直接リポジトリに置き、Github Pagesが提供するデフォルトのJekyllを使用し、カスタムドメインを設定していました。しかし、この方法には以下のような問題がありました:

  1. ソースコードを非公開にできない。_postディレクトリ内の記事は自由にコピーされ、他の場所で他人のコンテンツとして使用される可能性があります。
  2. 編集履歴を隠せない。ブログから突然削除したいコンテンツがあっても、リポジトリのソースコードの履歴をたどればファイルの変更履歴が丸見えになってしまいます。
  3. Gitalkが使えない。上記2つの問題はGithub Pro以上の有料アカウントで解決できます(この種の有料アカウントではプライベートリポジトリでGithub Pagesが利用可能)。しかし、issueへの書き込みを必要とするGitalkのようなコメントツールは使えなくなります。
  4. ローカルと本番環境のビルド結果が一致しない、またはエラーが発生した際に調査できない。Github Pagesが提供するJekyllは私たちにとってブラックボックスであるため、問題の切り分けが困難です。
  5. カスタム/サードパーティ製プラグインが使えない。Github Pagesがサポートしているのは一部のプラグインのみであるため、例えばカテゴリ別記事のページネーションを可能にするjekyll-paginate v2のようなプラグインは利用できません。

以上の理由から、私はコンパイル後のソースコードをGithub Pagesのコンテンツとして公開し、ソースコード自体は公開しないことに決めました。ブログのリポジトリには既にGitalkによって生成されたissueコメントが存在していたため、新たにリポジトリを作成し、新しいリポジトリをソースコードの保管場所としてプライベート設定にしました。そして、旧リポジトリは引き続きGithub Pagesの公開用リポジトリとして使用しますが、公開するのはコンパイル後のソースコードのみです。これにより、既存のコメントデータを保持しつつ、前述の問題を回避できます。私は毎回コンパイル後のソースコードをGithub Pagesにforceプッシュで公開しているため、ファイルの変更履歴を確認することはできず、ある程度プライバシーが保護され、複製のコストも高くなります。以下にこのプロセスの詳細を説明します。

全体の流れ

基本的な流れは次の通りです。旧リポジトリをA、新しいソースコード用のプライベートリポジトリをBとします。新しいpushが発生すると、BリポジトリのGithub Actionsがトリガーされ、そのActionsがコンパイル後のソースコード(_siteフォルダの内容)をAリポジトリにプッシュします。Aリポジトリは元々Github Pagesとして設定されており、カスタムドメインも設定済みなので、追加の処理は必要ありません。

詳細な手順

Github Actionsでは以下の概念を明確に理解する必要があります:

階層関係

大きい順に:

  1. スクリプト自体:actionsによって実行されるci.ymlファイルそのもの。
  2. ジョブ:設定されたjobsで、デフォルトでは並列実行されます。needsキーワードを使用して他のジョブへの依存関係を設定可能。
  3. ステップ:stepsで、ジョブ内で順次実行されます。各ステップは独自の環境コンテキストで実行されます。1つのジョブに無制限のステップを設定可能。
  4. アクション:すべてのステップがアクションを実行するわけではありませんが、アクションはステップ内で実行されます。具体的なコマンド(現在のディレクトリ表示、依存関係のインストールなど)が該当します。

他人のstepを使用する

Actionを使用すると、他の人が作成したstepを利用できるため、自分で記述する必要がありません。たとえば、ブランチをチェックアウトする必要がある場合、以下のように記述するだけで済みます:

1
2
3
4
- uses: actions/checkout@v2
with:
persist-credentials: fasle # false 是用 personal token,true 是使用 GitHub token
fetch-depth: 0

withは関連するパラメータであり、具体的な詳細は該当stepの説明を参照してください。

データの暗号化

ciファイルにPersonal Tokenやその他の機密データを公開したくない場合、暗号化して名前で参照する別の方法を使用する必要があります。ここで注意すべきは、暗号化データ間の違いです:

  1. GITHUB_TOKEN。自分のリポジトリに対してbuildやactionsを実行するだけであれば、リポジトリ設定で何もする必要はありません。actionsが実行されると、Githubは自動的にGITHUB_TOKENという環境変数をコンテキストに生成します。これは、現在のリポジトリにコードをプッシュするなど、認証が必要な場面で使用できます。
  2. Personal Token。現在のciがAリポジトリで実行されているが、Bリポジトリに対して何らかの操作を行う必要がある場合、Bリポジトリの管理者が生成したPersonal Tokenが必要です。その後、適切な権限を割り当てます。
  3. カスタム暗号化。ステップ2でBリポジトリのPersonal Tokenが生成された後、Aリポジトリでどのように使用するのでしょうか?この場合、secret(カスタム暗号化)を使用する必要があります。Aリポジトリの設定で、B_REPO_TOKENなどの変数名を定義し、先ほど取得したPersonal Tokenを貼り付けます。その後、secret.B_REPO_TOKENという形で参照できます。

具体的な手順

上記でかなり詳細に説明しましたので、以下にファイルをリストアップし、それぞれを分析します。必要な場合は、この内容をコピーして少し修正するだけで使用できます:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 该 ci 的名字,可以在仓库的 Github Actions tab 看到
name: Blog Generator

# 触发时机
on:
# 代码 push 到 master 分支的时候运行该 workflow
# TODO:不运行 commit 信息中包含特定关键词的 push
push:
branches: [master]

jobs:
# build-and-push 是 jobs 名字,随便取,可以有多个 jobs 默认并行
build-and-push:
runs-on: ubuntu-latest # 该 jobs 运行的环境
steps:
# 首先一般都是 checkout 当前的仓库代码,用官方的 actions/checkout@v2
- uses: actions/checkout@v2
with: # with 表示所需要的参数
persist-credentials: fasle # false 是用 personal token,true 是使用 GitHub token
fetch-depth: 0 # 保证能够 push 成功

# 设置 ruby 环境,这里用的也是官方的 actions
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6

# 安装依赖
- name: Install dependencies # 操作名字,会显示在 Github Actions 的任务输出界面,方便你 debug
run: bundle install # 运行的命令

# 打包静态资源
- name: Build Pages
run: bundle exec jekyll build

- name: Add Message
working-directory: ./_site # jekyll 默认 build 到 _site 目录,因此设置命令执行的目录为 ./_site
run: | # run 后面加个 ‘|’ 然后换行可以同时执行多个命令,每行一个
echo "www.xheldon.com" > CNAME
echo -e "# [Xheldon's Tech blog](https://www.xheldon.com)" > README.md

- name: Commit and Push # 将打包后的位于 _site 目录的文件 push 到 A 仓库即可
working-directory: ./_site
run: |
git init
git checkout -b master
git add -A
git -c user.name='github actions by ${{github.actor}}' -c user.email='NO' commit -m 'update'
git push "https://{%raw%}${{github.actor}}:${{secrets.X_BLOG_SITE}}{%endraw%}@github.com/Xheldon/x_blog.git" HEAD:master -f -q

ここで最後のステップについて説明が必要です。X_BLOG_SITEは私がカスタマイズした暗号化データで、値は設定したPersonal Tokenです。また、リモートにpushする場合、このCIが現在のリポジトリのみを操作するのであれば、リポジトリ名をハードコーディングする必要はなく、環境変数を以下のように記述できます:

1
git push "https://{%raw%}${{github.actor}}:${{secrets.GITHUB_TOKEN}}@github.com/${{github.repository}}{%endraw%}.git" HEAD:master -f -q

つまりgithub.XXXを使用して関連情報を参照できます。詳細なコンテキストパラメータの説明はこちらで確認できます。

travisとの違い

以前Travisを使用していましたが、両者の概念は基本的に大きく変わりません。最も顕著な違いは、Github Actionsでは他人が作成したactionsを参照できることです。これはまるで他人のパッケージを’require’できるようなもので、そのパッケージをメンテナンスする必要がなく、直接使用できます。より多くの遊び方が可能で、設定も少なく、再利用性が高くなっています。

- EOF -
この記事の初出: 無料でプライベートリポジトリを使用してGitHub Pagesを公開する - Xheldon Blog