GitHub Actionsを利用してFortranの自動生成ドキュメントをWebに展開する

# 概要
この[リポジトリ](https://github.com/everythingfunctional/ci_example)を参考に，プロジェクトに`.github/workflows/documentation.yml`を追加します．GitHubにpushすると，FORDのドキュメントが生成され，`gh-pages`ブランチにドキュメントがコピーされるようになります．
github-pagesにgh-pagesブランチを指定しておくと，WebからFORDのドキュメントが閲覧できるようになります．

# GitHub Actions
GitHub Actionsは，GitHubが提供する仮想の計算機環境です．リポジトリと連携することで，CI/CD環境として利用できます．詳しくは，公式の説明（https://github.co.jp/features/actions, https://docs.github.com/ja/actions ）を確認してください．

GitHub Actionsを利用すると，例えばリポジトリに変更をpushしたときに，そのpushをトリガーとして仮想計算機環境にOS等の環境を整え（コンテナを利用もしくは作成），リポジトリを参照して何らかの作業を行い，その結果をリポジトリに反映できます．

GitHub Actionsを利用することで，リポジトリに変更をpushすると同時に自動でドキュメントを生成してWebページとして展開しようというのが，この記事の目的です．ドキュメント作成を追加の作業として手動で行う必要があると，どうしても後回しになりがちです．人間は，人間にしかできない作業を頑張りましょう．

# FORDを用いたドキュメントの生成と展開
## FORDによるドキュメントの生成
Fortranプログラムのドキュメント生成には，FORDを利用します．FORDの使い方については[この記事](https://qiita.com/implicit_none/items/8fc065df6a295183b141)を参考にしてください．

FORDが主に対象としているのは，APIドキュメントやリファレンスに分類されるドキュメントの生成です．docmark呼ばれる記号を用いて，ソースコード内にドキュメント文字列を記述します．その後，ドキュメント作成に関する設定（プロジェクト情報，処理するファイルがあるディレクトリ情報等）を記述したファイルをFORDに渡すことで，html形式のドキュメントを生成します．

[参考にしているリポジトリ](https://github.com/everythingfunctional/ci_example)のソースファイル`src/ci-example.f90`では，関数`create_greeting`の動作を説明するドキュメント文字列が記述されています．

```Fortran:src/ci-example.f90
module ci_example
    implicit none
    private

    public :: create_greeting
contains
    pure function create_greeting(name) result(greeting)
        !! Given a [name], construct a [greeting] for them
        character(len=*), intent(in) :: name
        character(len=:), allocatable :: greeting

        greeting = "Hello, " // name // "!"
    end function
end module
```

ドキュメント生成に関する設定は，`doc/ford-front-matter.md`です．この設定によると，生成されたドキュメントは，`doc/ford_site`ディレクトリに出力されます．

FORDでドキュメントを生成するには，下記のようにコマンドを実行し，FORDにドキュメント生成の設定を渡します．**プロジェクトルートで実行し，相対パス付きで設定ファイルを指定する**と覚えておくとよいでしょう．
```console
ford doc/ford-front-matter.md
```

## GitHub Actionsによる展開
GitHub Actionsを利用するには，ワークフロー（GitHub Actionsで実行したい一連の作業）をYAML形式で記述し，`.github/workflows`ディレクトリに置きます．[参考にしているリポジトリ](https://github.com/everythingfunctional/ci_example)の場合，ドキュメント生成に関するワークフローは`.github/workflows/documentation.yml`に記述されています．

```yaml:.github/workflows/documentation.yml
name: Build and Deploy Documentation

on: [push, pull_request]

jobs:
  documentation:
    runs-on: ubuntu-22.04

    env:
      FC: gfortran
      GCC_V: 12

    steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Install Dependencies Ubuntu
      run: |
        sudo apt-get update
        sudo apt install -y gfortran-${GCC_V} python3-dev graphviz
        sudo pip install ford markdown==3.3.4
    - name: Build Developer Documentation
      run: |
        ford doc/ford-front-matter.md
    - name: Upload Documentation
      uses: actions/upload-artifact@v2
      with:
        name: documentation
        path: doc/ford_site
        if-no-files-found: error

    - name: Broken Link Check
      if: ${{ github.ref == 'refs/heads/main'}}
      uses: technote-space/broken-link-checker-action@v1
      with:
        TARGET: file://${{ github.workspace }}/ford_site/index.html
        RECURSIVE: true
        ASSIGNEES: ${{ github.actor }}

    - name: Deploy API Documentation
      uses: JamesIves/github-pages-deploy-action@4.1.0
      if: ${{ github.event_name == 'push'  &&  github.ref == 'refs/heads/main' }}
      with:
        branch: gh-pages
        folder: doc/ford_site
```

私自身完全に把握しているわけではありませんが，一つずつ解説をしていきます．

--
```yaml
name: Build and Deploy Documentation
```
これは動作するワークフローの名前で，特に制約はありません．判りやすい名前を付けておけばよいでしょう．

--
```yaml
on: [push, pull_request]
```
これはどういうときにワークフローを実行するかの指定です．リポジトリにpushしたときとpull-requestが送られてきたときにワークフローが実行されます．もう少し細かい指定をしたい（例えば，pull-requestがメインのブランチにマージされた時にだけワークフローを実行したい）という要望もあると思います．そういった条件を記述することも可能ですが，ここでは触れません．

--
```yaml
jobs:
  documentation:
    runs-on: ubuntu-22.04
```
`jobs:`の節では，ワークフローで実行する各処理を記述します．documentationという名前のジョブを，ubuntu-22.04コンテナ上で実行するという指定です．実際に行う作業は，`setps:`以下に記述します．

--
```yaml
    env:
      FC: gfortran
      GCC_V: 12
```
ジョブの中で有効な環境変数の設定です．ドキュメントの作成過程でFortranのソースのプリプロセスを行う場合があるので，Fortranコンパイラにgfortranを使うことが記述されています．

--
`steps:`以降に，実行するコマンドなどを記述します．ここでは，実行するコマンドを記述する`run:`と，外部のワークフローを利用する`uses:`が利用されています．実行するジョブを順に見ていきます．

```yaml
    - name: Checkout code
      uses: actions/checkout@v3
```
`runs-on`で指定したコンテナ内に，リポジトリのコードをチェックアウトします．チェックアウトには，GitHubが用意しているアクションを利用しています．

--
```yaml
    - name: Install Dependencies Ubuntu
      run: |
        sudo apt-get update
        sudo apt install -y gfortran-${GCC_V} python3-dev graphviz
        sudo pip install ford markdown==3.3.4
```
次に，UbuntuにgfortranやFORDなど，必要なパッケージをインストールします．参考にしているリポジトリの作成者によると，FORDはmarkdownの最新バージョンを用いるとうまく動作しないため，バージョンを指定してインストールしているとのことです．

--
実行する環境を整えた後は，ドキュメントを生成します．

```yaml
    - name: Build Developer Documentation
      run: |
        ford doc/ford-front-matter.md
```
FORDを実行してドキュメントを生成します．`run:`には，[上](#fordによるドキュメントの生成)で紹介したコマンドがそのまま書かれています．FORDの設定ファイルの置き場所を変更した場合，あるいは自身のプロジェクトに適用する場合は，このコマンドを編集すればよいということが判ります．

--
```yaml
    - name: Upload Documentation
      uses: actions/upload-artifact@v2
      with:
        name: documentation
        path: doc/ford_site
        if-no-files-found: error
```
生成したドキュメントを，コンテナの中からリポジトリへアップロードします．アップロードには，GitHubが用意しているアクションを利用します．`path:`で指定されたディレクトリがアップロードされます．この`path:`で指定されたディレクトリは，FORDの設定でドキュメントの出力ディレクトリとして指定されたディレクトリです．FORDの設定を変更した際は，この`path:`も変更する必要があります．

--
```yaml
    - name: Broken Link Check
      if: ${{ github.ref == 'refs/heads/main'}}
      uses: technote-space/broken-link-checker-action@v1
      with:
        TARGET: file://${{ github.workspace }}/ford_site/index.html
        RECURSIVE: true
        ASSIGNEES: ${{ github.actor }}
```
作成したhtmlファイル内のリンクが切れていないかをチェックします．ここでは，新たに`if:`が出てきています．`if:`を用いてpushされたブランチの名前をチェックし，それが`main`ブランチの場合だけアクションを実行します．
このリンクチェックは必須ではないので，自身でワークフローを作成する場合は実行しなくても（ワークフローから削除しても）問題はありません．

--
```yaml
    - name: Deploy API Documentation
      uses: JamesIves/github-pages-deploy-action@4.1.0
      if: ${{ github.event_name == 'push'  &&  github.ref == 'refs/heads/main' }}
      with:
        branch: gh-pages
        folder: doc/ford_site
```
最後にドキュメントを展開します．展開といっても，アクションの中で行われるのは，リポジトリに`gh-pages`というブランチを作成してそこにアップロードしたドキュメントを置くだけです．ドキュメントを置くだけでなぜ展開と言っているのかというと，リポジトリの内容をウェブページとして公開する[GitHub Pages](https://docs.github.com/ja/pages/getting-started-with-github-pages/about-github-pages)の利用を想定しているからです．

そのため，公開するにはこのワークフローを実行するだけでは不十分で，作成された`gh-pages`ブランチをWebサイトとして公開する設定も必要です．

## 公開設定
公開設定は，リポジトリのSettings > Pagesから行います．

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/c7684142-f2da-d40a-763d-2871f899b1ac.png)
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/40cb5757-4d48-83f7-fea0-adb201de102a.png)

PagesのGitHub Pages > Build and deploymentのSourceをDeploy from a branchとし，Branchから`gh-pages`を選択し，Saveします．ここでブランチを選択するために，一度ワークフローを実行して，全てエラー無く完了している必要があります．
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/fe2c5b44-c1b0-73df-20d5-3fa13efe49c9.png)

設定を終えると，設定したブランチ（＝ドキュメント）が静的Webサイトとして確認できるようになります．URLは `https://アカウント名.github.io/リポジトリ名/`です．参考にしたリポジトリのドキュメントは[ここ](https://everythingfunctional.github.io/ci_example/)から見ることができます．

# まとめ
退屈なことはGitHub Actionsにやらせよう