GitHub Pages の GitHub Actions で AsciiDoc の生成を試す

## 概要

2022-08-06 時点で、新たなレポジトリで GitHub Pages を使おうとしたら、 GitHub Actions (Bata) が増えていたので、人柱として移行してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326797/336985b2-0524-aa69-ea1b-370a457ff21a.png)

### 参考

* [GitHub Pages: Custom GitHub Actions Workflows (beta) | GitHub Changelog](https://github.blog/changelog/2022-07-27-github-pages-custom-github-actions-workflows-beta/)
  2022-07-27 の記事

## 使用感
Beta ですが、静的ファイル置き場だけのブランチを作らなくてよくなったのは良いですね。

* デプロイ用にブランチを作らなくてもよくなった
* ジョブが2つだったのが1つにまとめられた

## 詳細

### 使用前の詳細

もともとは Deploy from a branch の設定で、AsciiDocを静的なHTMLファイルに変換したものを gh-pages のGitブランチに突っ込んだ、それをデプロイしていました。

このため、ブランチ構成は大まかに次のようになります。

* main (Git branch)
  * .github/workflows/gh-pages.yaml
  * docs/
    * Makefile
    * index.adoc
  * gh-pages.gitignore ... pg-pagesブランチ用の .gitignore

* gh-pages (Git branch) ... GitHub Actions のデプロイ先
  * index.html
  * .gitignore

ビルドジョブの後、自動でデプロイジョブが動きます。これはhtmlファイルが閲覧可能になるまで画面上で追う場合、2つのジョブの経過を追う必要があり、Actionsタブを複数回クリックする必要が出てきます。(大したことではないけどUI上はダサい。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326797/1c334b88-e9b1-fa1e-5c8a-4838171401cd.png)

#### .github/workflows/gh-pages.yaml

独自処理としては、次のものがあります。

* gh-pages.gitignore を dist にコピー
* index.adoc などのAsciiDoc文書をHTML文書に変換し、その出力先を dist/ にする

```yaml
name: Convert AsciiDoc documents to HTML

on:
  push:
    branches: [ "main" ]

jobs:
  adoc_build:
    runs-on: ubuntu-latest
    name: convert asciidoc to html
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
    - name: Get build container
      id: adocbuild
      uses: tonynv/asciidoctor-action@master
      with:
          program: "cd docs && make adoc"
    - name: copy .gitignore file
      uses: canastro/copy-file-action@master
      with:
        source: "gh-pages.gitignore"
        target: "dist/.gitignore"
    - name: Deploy
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: dist/
```

### 使用後の詳細

もともとは Deploy from a branch の設定で、AsciiDocを静的なHTMLファイルに変換したものを gh-pages のGitブランチに突っ込んだ、それをデプロイしていました。

このため、ブランチ構成は大まかに次のようになります。

* main (Git branch)
  * .github/workflows/pages.yml ... 名前は pages.yml 固定
  * docs/
    * Makefile
    * index.adoc
  * ~~gh-pages.gitignore~~ ... pg-pagesブランチ用の .gitignore は不要

* ~~gh-pages~~ (Git branch) ... GitHub Actions のデプロイ先も不要になった

一つのジョブでビルドとデプロイを追跡できるようになった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326797/fcb8f4fe-46db-c059-2af6-0ac819db944f.png)

ビルドとデプロイのステップが1画面で確認できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326797/1812638a-4231-53b3-019b-c2617126a7cc.png)

#### .github/workflows/pages.yaml

基本的には雛形そのままです。★部分が主な変更箇所です。
YAMLファイルは長くなっていますが、そんなに難しくはないと思います。

```yaml
name: Convert AsciiDoc documents to HTML

on:
  push:
    branches: [ "main" ]

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: "pages"
  cancel-in-progress: true

jobs:
  # Build job
  build:
    runs-on: ubuntu-latest
    name: convert asciidoc to html
    steps:
    - name: Checkout
      uses: actions/checkout@v3
    - name: Get build container              # ★ 流用
      id: adocbuild                          # ★ 流用
      uses: tonynv/asciidoctor-action@master # ★ 流用
      with:                                  # ★ 流用
          program: "cd docs && make adoc"    # ★ 流用
    - name: Build with Jekyll
      uses: actions/jekyll-build-pages@v1
      with:
        source: ./dist              # ★ ひな型から変更
        destination: ./_site
    - name: Upload artifact
      uses: actions/upload-pages-artifact@v1

  # Deployment job
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v1
```

## おまけ: AsciiDoc文書のビルドに使ったMakefile

実際は使っているのはもう少し複雑ですが、少し簡略化したものは次のようになります。

* docs/
  * Makefile
  * index.adoc
  * header.adoc 

### docs/asciidoc.mk

```Makefile
IMAGES_DIR=images
CP_OPTS=-n -l
ROUGE_STYLE=monokai_sublime

AD_OPTS_HTML5_COMMON=\
--backend=html5 \
-a imagesdir=$(IMAGES_DIR)

AD_OPTS_HTML5_ROUGE=\
$(AD_OPTS_HTML5_COMMON) \
-r asciidoctor-diagram \
-a source-highlighter=rouge \
-a rouge-style=$(ROUGE_STYLE)

AD_OPTS_HTML5_STEM=\
$(AD_OPTS_HTML5_COMMON)
```

### docs/Makefile

画像は docs/images があれば dist/ にコピーします。
画像のコピーは1回きりなので `mkdir_and_copy` という疑似ターゲットのなかで必要時にディレクトリ作成とコピーを行っています。

```Makefile
BASE_DIR=..
DOC_ROOT=.

DEST_DIR=$(BASE_DIR)/dist
SRC_IMAGES_DIR=$(IMAGES_DIR)
DST_IMAGES_DIR=$(DEST_DIR)/$(IMAGES_DIR)

include $(DOC_ROOT)/asciidoc.mk

HTML_LIST=\
mkdir_and_copy \
$(DEST_DIR)/index.html

.PHONY: adoc mkdir_and_copy

adoc: $(HTML_LIST)

mkdir_and_copy:
	mkdir -p $(DEST_DIR)
	-test ! -d $(SRC_IMAGES_DIR) || mkdir -p $(DST_IMAGES_DIR)
	-test ! -d $(SRC_IMAGES_DIR) || cp $(CP_OPTS) $(SRC_IMAGES_DIR)/* $(DST_IMAGES_DIR)/

$(DEST_DIR)/%.html: %.adoc header.adoc
	asciidoctor --trace $(AD_OPTS_HTML5_ROUGE) -o "$@" "$<"
```

たた、汎用性を考えなければ次の方がシンプルです。

画像がないときは、 `mkdir_and_copy` を消してしまう。

```Makefile
$(DEST_DIR)/%.html: %.adoc header.adoc
	mkdir -p $(DEST_DIR) 
	asciidoctor --trace $(AD_OPTS_HTML5_ROUGE) -o "$@" "$<"
```

画像があるときは、出力用の画像ディレクトリを常に作り、コピーする

```Makefile
mkdir_and_copy:
	mkdir -p $(DST_IMAGES_DIR)
	cp $(CP_OPTS) $(SRC_IMAGES_DIR)/* $(DST_IMAGES_DIR)/

$(DEST_DIR)/%.html: %.adoc header.adoc
	asciidoctor --trace $(AD_OPTS_HTML5_ROUGE) -o "$@" "$<"
```

### docs/index.adoc

```asciidoc
ifndef::leveloffset[]
:toc: left
:toclevels: 3
:icons: font

include::header.adoc[]
endif::[]

== Title
...
```

### docs/header.adoc

この例では空ファイルです。

ページが増えてきたらこんな感じで追加しています。
「Index | Foo | Bar | Baz」 みたいなメニュを付けます。

```asciidoc
ifndef::leveloffset[]
ifeval::["{backend}" == "html5"]
<<index.adoc#,Index>> {vbar}
<<foo.adoc#,Foo>> {vbar}
<<bar.adoc#,Bar>> {vbar}
<<baz.adoc#,Baz>> +
endif::[]
endif::[]
```

以下、シンプルにしたい人向けの補足です。

次の ifeval はPDF向けのものです。PDFではヘッダー部のリンク集は煩わしいので HTMLの時だけ読み込む指定です。PDFを作るつもりがないなら不要です。

```asciidoc
ifeval::["{backend}" == "html5"]
// ～
endif::[]
```

次の部分は、別のファイルから `include::foo.adoc[leveloffset=+1]` などとファイル中に取り込む場合にはヘッダを出さないためのものです。 include で読み込むつもりがないなら不要です。

```asciidoc
ifndef::leveloffset[]
// ～
endif::[]
```