自作のPythonコードのドキュメント化の話

# READMEが終わらない、、

コードを一通り作り終わり、さぁ公開するか！とするときに、READMEを書かなきゃいかんかったことを思い出し。
書き始めるのですが、、、書いても書いても終わらない、、、

そもそも、自分が人のライブラリ使うときは使ってみてる人のブログを見て、専用のdocumentページをみて、それでもどうにもならんかったらソースを見て、、と、READMEにそこまで期待するわけじゃないんですよね。。

きちんとしたdocumentationの方法と、公開の仕方をちゃんと調べますか。。

# ドキュメントを生成しよう
## pydoc
これまでみて見ぬふりを決め込んでたましたが、そうもいかんですね。

手元のubuntu dockerで実行、、、できない。
pipで入れるもの、、でも無いんですね。
私の環境ではpythonはOSの標準のものを使うようにしてますし、それに合わせてaptで導入。

```
$ apt install python-dev-is-python3
```

まずは、試してみる。

```
$ cd ./src
$ pydoc <My Pkg>
$ pydoc <My Pkg>.<My Module>
```

ドキュメント化したいファイルを指定するのではなく、モジュールを指定する方法となります。
pypiに上げるつもりで整理していると、./src/<MY PKG>というようなディレクトリ配置にしてるでしょうから、srcの直下で上記のコマンドを打つ感じです。

雰囲気として、自分がローカルで引用するときに使うような用途なんですかね。

htmlとして出力もできるし、ウェブサーバとして起動することもできるとのことだけど、、
Github Pagesか、何かしらのウェブサービスに乗っける方法が今回のゴールイメージなので、これじゃない。

## sphinx
まさにまとめて下さってる方が。
https://qiita.com/kinpira/items/505bccacb2fba89c0ff0

ただ、今回はすでに作成済みのパッケージを使うので、htmlファイル生成は以下の方法を参照させていただきます。
http://capm-network.com/?tag=Python_%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E7%94%9F%E6%88%90

```
$ pip3 install sphinx
$ sphinx-apidoc -F -o docs/ src/
$ cd ./docs
$ make html
```

ちなみに私の環境だとmakeも入れてないので、まずは apt install make からなんですが。。
実行してみると、htmlファイルとそれに使われるディレクト群はいいとして、、結構ワラワラ生成されるな。。
これイランものはgitに乗っけないような配慮をしたところだな。。

## sphinxの生成物

上記で生成したディレクトリを見ると、以下のような構造になっている。

```
$ tree ./
./
|-- Makefile
|-- _build
|   |-- doctrees
|   |   |-- <My PKG>.doctree
|   |   |-- <My PKG>.searchpath.doctree
|   |   |-- environment.pickle
|   |   `-- index.doctree
|   `-- html
|       |-- _modules
|       |   |-- <My PKG>
|       |   |   |-- <My Module>.html
|       |   `-- index.html
|       |-- _sources
|       |   |-- <My PKG>.rst.txt
|       |   |-- <My PKG>.searchpath.rst.txt
|       |   `-- index.rst.txt
|       |-- _static
|       |   |-- alabaster.css
|       |   |-- basic.css
|       |   |-- custom.css
|       |   |-- doctools.js
|       |   |-- documentation_options.js
|       |   |-- file.png
|       |   |-- jquery-3.5.1.js
|       |   |-- jquery.js
|       |   |-- language_data.js
|       |   |-- minus.png
|       |   |-- plus.png
|       |   |-- pygments.css
|       |   |-- searchtools.js
|       |   |-- underscore-1.3.1.js
|       |   `-- underscore.js
|       |-- <My PKG>.html
|       |-- <My PKG>.searchpath.html
|       |-- <My PKG>.html
|       |-- index.html
|       |-- objects.inv
|       |-- py-modindex.html
|       |-- search.html
|       `-- searchindex.js
|-- _static
|-- _templates
|-- conf.py
|-- <My PKG>.rst
|-- <My PKG>.searchpath.rst
|-- index.rst
```

htmlディレクトリ配下だけあれば、Web公開には事足りそう。
で、よくお世話になってるパッケージを見ると、、docs配下に_build以外をおいている、、。
必要に応じて手元で生成できるようにはしておくけど、生成物は.gitignoreで排除してますね。

以下のGithub Pagesの公開の章で改めて考えます。

## 備考　pypi向けのアップ
sphinxで生成したファイルをpypiにアップする。

https://pythonhosted.org/an_example_pypi_project/buildanduploadsphinx.html
https://pypi.org/project/Sphinx-PyPI-upload/

でも大体のパッケージってpypiにはほとんど情報書かず、gitや自組織のdocページへのリンクを貼ってるんですよね。。
これは見送りで。

# 公開しよう
## Github Pages
https://docs.github.com/en/github/working-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site

「指定のブランチの指定のディレクトリのコンテンツを、webpageとして公開する」。
。。。ちと考えないといけないですね。。

初心者の私から見ると、以下のどちらかの使い方を選ぶ感じでしょうか。

1. ドキュメント配置専用の空ブランチ（ディフォだと"gh-pages")を新たに作って、そこにコンテンツを置く
2. mainブランチの指定のディレクトリ（/docとか？）にコンテンツをおく

実際の用途を考え得ると、ソースの変更・テストと、ドキュメント化は、２ステップに別れる作業なんですよね。
なので、想定するワークフローは下のどちらかでしょうか。

A.「ソースを更新してテストする」「gitに上げる」「（Github Actionsとかで自動的に）doc化する」「docをgitに上げる」
B.「ソースを更新してテストする」「doc化する」「ソースとdocを一緒にgitに上げる」

Aでやりたいなら1、Bでやりたいなら2、てとこでしょうかね。
Aを2で実施できる方法もsphinxのユーザ会で紹介されてましたけど、gitに上げたものが自動で更新されるのはgit初級者からするとややっこしい。。チーム開発していれば他者がpushするのも当たり前なわけで、違和感ないのだろうけど、私はまだその領域にはたどり着けてないですね。。
https://sphinx-users.jp/cookbook/githubaction/index.html

gitでよく使わせていただいているパッケージの事例を参考にさせていただこうかなとgitを見ると、、うん、そもそもGithub Pagesつかっとらんですね。。
上のgitのdocsの掲載事例をみるに、gitでコード持ってった人がsphinxでdocを生成できるように、sphinx用の設定ファイルはアップしておくけど、sphixで生成したWebコンテンツ自体は別の方法で管理する、ということでしょうか。
上記のパターンに当てはめると、Aと1のペアに相当する方法ってことでしょうか。
一回その組み合わせで方法確立するか。

## Doc専用ブランチの作成と、公開（初回編）
以下の手順に則って、レポジトリに対してgp-pagesの新規追加をする。

```
$ cd <PKG Directory>

# Sphinxでhtmlファイルを生成する
$ sphinx-apidoc -F -o docs/ src/
$ cd ./docs

# コンフィグファイル(conf.py)にて、以下を修正。
#  1. import sysと、sys.path.insert(..)のコメントアウトを外す。
#     これをしないと、モジュールが見つからないというエラがー出ててしまう。
#  2. copyright, authorを適切に記入
# 
# その後、改めてmake
$ make html

# first commitに戻す。（もっときれいな方法あるとは思うけど、、）
# 上記で生成したファイルは、git addしてないので、docs/_build/html配下はまるまる残ってる、、、はず、、
# addしてても、標準の.gitignoreに_buildが入っているはずなので、やっぱ残ってるはず、、、
$ git log | grep "^commit" | tail -n1 | cunt -d " " -f 2 | xargs -n1 git reset --hard

# 不要なファイルを消しとく
$ rm <不要ファイル群> #README.rstやLICENSE, .gitignoreなど、、かな、、、

# htmlファイルをルートに持っていく
# Github Pagesで公開対象のディレクトリを_build/htmlに限定しておけばいい気もするけど、、現状pros/consが思いつかないので、一応絞っとく。
$ mv ./docs/_build/html/* ./
$ rm -rf ./docs

# Webページ公開用のブランチを作る
$ git checkout -b gp-pages

# Gitにアップ
$ git add .
$ git commit -m "First Commit for gh-pages"
$ git push -u origin gh-pages

# Github Pages設定を有効化する
# https://docs.github.com/en/github/working-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site
# Branchでph-pagesを指定。ディレクトリ指定はしない（gitのルートは以下のコンテンツをそのまま読み込む）。

# mainブランチに戻る
git checkout main

```

## Docの更新（２回目以降）

```
# まず、変更分をコミットして、gitに上げておく。
$ cd docs
$ make html
$ git checkout gh-pages
$ mv ./docs/_build/html/* ./
$ rm -rf ./docs
$ git commit -m "Commit MSG"
$ git push -u origin ph-pages
```

## 処理の自動化
Github Actionsで、mainブランチがpushを受けたら、上記のDocの更新を実行して、gh-pagesにプッシュする、って方法。

pushの認証は、いくらGuthubのSecretsを使うと言っても流石にパスワードを登録するのも気持ち悪いし、レポジトリ専用のsshキーペアを作り、sshでプッシュする方法を使うことにする。
以下の方法を使わせていただく。
https://sphinx-users.jp/cookbook/githubaction/index.html

### ssh鍵の作成と、gitへの登録
手元でssh鍵を作り、公開鍵をレポジトリのDeployment keyに登録しておく。
秘密鍵はSecretに登録し、Actionで都度呼び出してssh接続に使う。
鍵の登録方法は、上記のsphinxのサイトを参照。

今回は、Secretsに"UPLOADKEY"という名称で登録する。

### Gtihub Actions用のコンフィグ調整
Github Actionsでは、処理は/home/runner/work/<Repository Name>/<Pkg Name>で実行されるっぽい。
この際、conf.pyでソースディレクトリのパスを通すところをちょっと工夫してやらないといけない。

```
$ vi ./docs/conf.py
import os
import sys
sys.path.insert(0, os.path.abspath('../src'))
```

make htmlはおそらくdocsのは以下で実施するので、そこからの相対パスでソースの配置場所を動的に設定する。

### Github Actions
mainレポジトリの.git/workflowに、以下を配置する

```
$ cat .github/workflow/main.yaml

name: Generate Document

on:
  push:
    branches: [ main ]
  workflow_dispatch:

jobs:
  documemtation:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/setup-python@v2
        with:
          python-version: '3.x'
      
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
　　　　  # fetch-depthの設定を入れないと、最新のレポジトリしか持ってこないので、gh-pagesがなくてチェックアウトできなくなる。

      - name: Install sphinx
        run: pip3 install sphinx

      - name: Install requirements
        run: pip3 install -r requirements.txt

      - name: Make HTML
        run: make html
        working-directory: ./docs

      - name: Change Branch
        run: git checkout gh-pages

      - name: Clean directories
        run: find -mindepth 1 -maxdepth 1 -type d -not -name "docs" -and -not -name ".git" | xargs -n1 rm  -rf

      - name: Arrange html files
        run: |
          mv -f ./docs/_build/html/* ./
          rm -rf ./docs

      - name: Setup SSH
        run: |
            mkdir ~/.ssh
            ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
            echo "${{ secrets.UPLOADKEY }}" > ~/.ssh/id_rsa
            chmod 400 ~/.ssh/id_rsa

      - name: Commit and Push
        env:
          GITHUB_USER: "<User Name>"
          GITHUB_EMAIL: "<Mail Address>"
        run: |
          git config --local user.name "${GITHUB_USER}"
          git config --local user.email "${GITHUB_EMAIL}"
          git add .
          git commit -m "Auto documentation"
          git push origin gh-pages
```

とりあえずちゃんと動きますね。
でも、思ったほどドキュメントサイト見やすくないな。。。デザインが悪いのだろうか。
もうひとひねり必要そうですね。

まぁそれはおいおい。