Docker, GitHub Actions を組み合わせた Julia パッケージ開発環境を作るよ．

# Notification

これは 2019 年１２月ゴロに書いた記事ですが. 
2020年 9 月現在 の Julia 1.5 系でも動作できるはずです．適宜読み替えてください．

# 本日は 

- アドベントカレンダー空いていたので書きました．
  - [２０１９年クリスマスシーズンからプログラミング言語 Julia を始めるため，第１歩からN(>=1)歩進む手引き](https://qiita.com/SatoshiTerasaki/items/a2f3e4bb0485c1af8254)
を書きましたがみなさん真に  N > 1　歩進みましたでしょうか？

- 以前，PkgTemplates.jl をベースに Julia のパッケージを開発する方法を書きました．

  - [PkgTemplates による Julia パッケージの作り方（前半）](https://qiita.com/SatoshiTerasaki/items/24443f20852ed60968bf)
  - [PkgTemplates による Julia パッケージの作り方（後半）](https://qiita.com/SatoshiTerasaki/items/f43a7730bcf57f4b9572)

これによると

 - Travisを用いたCIやパッケージのドキュメントをGitHubのリポジトリでホスティングできるようになります．
 - (もちろん Julia のPkgを用いて generate することもできますが PkgTemplates.jl はこの作業を簡略化してくれます．)

# 今回は

- Travis でしていたようなワークフロー（Pull Requestしたときにその内容がテストを通るか，masterブランチにマージされたときにdevのドキュメントを生成し `github.io` で公開する作業）を GitHub Actions で賄うようにします．
- そして開発作業を Docker コンテナの内部で閉じれるようにする．具体的にはホスト環境に Julia，が導入されていなくても
    - Jupyter Notebook を手元のブラウザ上で閲覧し Julia を実行する
    - REPLベースで Julia を動かすようにする
    - ドキュメントを生成しそれを手元のブラウザ上で閲覧するようにする

# はじめよう

## PkgTemplates.jl の導入

- [PkgTemplates.jl](https://github.com/invenia/PkgTemplates.jl) の 0.7 を導入します．これは GitHub Actions のテンプレートを生成するために必要です.
- 2019/12/21 現在では 0.6 が安定版になっていますので．master ブランチの物を導入します．

```julia
Pkg> dev PkgTemplates
Pkg> st
...
...(いくつかパッケージとそのバージョンが並ぶ)
...
PkgTemplates v0.7.0-DEV [`~/.julia/dev/PkgTemplates`]
...
...（0.7.x になっていれば OK）
...
```

## テンプレートの準備

- 下記のようなスクリプトを書きます．そしてそれを実行します．

```julia
using PkgTemplates

t = Template(;
             dir="~/work",
             julia=v"1.3",
             plugins=[
                 License(; name="MIT"),
                 Git(; manifest=false, ssh=true),
                 GitHubActions(),
                 Documenter{GitHubActions}(),
             ],
)

t("MyWorkflow")
```

`t` にいれる文字列は将来あなたのパッケージの名前になるものになります．

- 以前はパッケージが生成される場所は `~/.julia/dev` 固定でしたが dir でどこに置くのかを指定できます．
- `plugins` には
  - ライセンス(ここでは MIT ライセンスとしている)
  - Git の設定 
  - リモートは個人的にSSHを使うため true を指定
  - `Manifest.toml` を初期コミットに含めない
  - GitHub Actions を使うためのおまじない
を含めておきます．

- `t("MyWorkFlow")` を実行すると `~/work/MyWorkflow` が生成されます．

これでほぼ完成です．[PkgTemplates による Julia パッケージの作り方（後半）](https://qiita.com/SatoshiTerasaki/items/f43a7730bcf57f4b9572) と同様にリモートのリポジトリの受け皿を生成してそれに向けてローカルリポジトリをpushすればOKです．プッシュしたあと 

Actions に行って CI が流れていればOK．これでGitHub Actionsで自動テストをする基盤が出来上がります．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/6e21b3c8-8c08-8e45-37b7-224a06d86ca7.png)

## DocumenterTools からドキュメント生成の Token を入手

- [PkgTemplates による Julia パッケージの作り方（後半）](https://qiita.com/SatoshiTerasaki/items/f43a7730bcf57f4b9572) で述べているようにデプロイキーと DOCUMENTER_KEY を生成します．これらは DocumenterTools.jl を用いて生成されます．
- `DOCUMENTER_KEY` を リポジトリの Settings -> Secrets -> に進み DOCUMENTER_KEY を追加します．
- デプロイキーも Deploy keys に documenter という名前で追加します．要するにTravisでやっていた秘密の呪文をGitHubの方に入れただけですね．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/38ce5c1b-56ad-7adf-7b83-068c88ba1e25.png)

これでパッケージ生成してGitHub Actions と連携することができました．GitHub Actions で何がやっているのかを知るには

`MyWorkflow/.github/workflows` 直下に `ci.yml` というのがあるのでそれを眺めてください．

- https://github.com/marketplace/actions/setup-julia-environment を見ると理解が深まるかもしれません．

# ここから Docker の導入，カスタマイズしていく

- リポジトリ直下に次を追加します:
  - [Dockerfile](https://github.com/terasakisatoshi/MyWorkflow.jl/blob/v0.1.0/Dockerfile)
  - [docker-compose.yml](https://github.com/terasakisatoshi/MyWorkflow.jl/blob/v0.1.0/docker-compose.yml)
  - [Makefile](https://github.com/terasakisatoshi/MyWorkflow.jl/blob/v0.1.0/Makefile)

ただ追加するだけですので，既存のパッケージにも使えるはずです．

- リポジトリが重くなるとコンテキスト作成に時間がかかるので [.dockerignore](https://github.com/terasakisatoshi/MyWorkflow.jl/blob/v0.1.0/.dockerignore) を使ってDockerイメージ生成に不要なディレクトリを追加しておくと良いでしょう．
- Jupyter notebook と連携させることを考えると必要に応じてPython，Jupyterが生成する不要な物をバージョン管理から外すために [.gitignore](https://github.com/terasakisatoshi/MyWorkflow.jl/blob/v0.1.0/.gitignore#L26-L37) を追加しても良いでしょう．ちなみに GitHubで生成される `.gitignore` の Julia 版は[こちらから](https://github.com/github/gitignore/blob/master/Julia.gitignore)入手できます．

## カスタマイズ後の開発ワークフロー

### まずはビルド

リポジトリ直下に移動して `make build` を実行します．これは Docker または Docker-compose を利用する際に用いるイメージをビルドします．これはターミナルで次を実行することと等価です．

```console
$ docker-compose build
$ docker build -t myjulia .
$ docker-compose run --rm julia julia --project=. -e 'using Pkg; Pkg.instantiate()'
```

- 最後の三行目はローカルのJuliaで次を実行することとに対応しています．

```console
$ julia
julia> ] # switch to Pkg mode
pkg> activate
pkg> instantiate
```

- instantiate は `Manifest.toml` を生成・更新するために使われます．既存のパッケージで Manifest.toml がバージョン管理されている時は instantiate は省いても良さそうです．各自の環境に応じて使い分けてください．



### 実行（通常のREPLのようにして）

手元の環境が Docker または Docker Compose が整っていれば手元にJulia環境がなくても次のように Julia をコンテナ内で動かすことができます．

```console

$ docker-compose run --rm julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.3.0 (2019-11-26)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> using Example

julia> names(Example)
3-element Array{Symbol,1}:
 :Example
 :domath
 :hello

julia> hello("World")
"Hello, World"
```

- References:
  - [docker-compose rm container after docker-compose run #2568](https://github.com/docker/compose/issues/2568)
  - [docker-compose [stop | kill | rm] does not cleanup docker-compose run <service> #2184](https://github.com/docker/compose/issues/2184)

### 実行 (通常の Jupyter Notebook のようにして)

- 次を実行すると手元のブラウザ上で `localhost:8888` にアクセスすることで Jupyter 上で Juliaが動きます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/9f34084b-44ee-b2ac-9799-737d0aaa1523.png)

ちなみに上で紹介した Dockerfile は jupytext で ipynb 形式を jl 形式にしてバージョン管理しやすくなっています．
使いかは下記の References を参考にしてください． ipynb はバージョン管理せず対応する jl ファイルをバージョン管理する方式をとる感じです．

- References
  - [jupytext](https://github.com/mwouts/jupytext)
  - [Jupyter notebook を管理しやすくする Jupytext を使ってみた](https://qiita.com/cfiken/items/8455383f32ee19dfbba3)

```
$ docker-compose up jupyter
...
... (いくつかメッセージが流れる)
...
```



### ドキュメントを閲覧したい

- 次を実行すると手元のブラウザ上で `localhost:8000` にアクセスすると見られます．

```
docker-compose up web
...
... コンテナ内でJuliaが起動しドキュメントが生成される
...
```

何も書いてないので下記のようなページのみが表示されます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/706ce985-6e4d-c08b-abbd-6e5ef588e8ea.png)

以上

# まとめ

- PkgTemplates.jl の新しい機能を先取りしました．GitHub Actions を用いてCIを進める基盤を作ることができました．
- Dockerで開発をとじるワークフローを提案しました．
  - ここでは書いてませんが，起動したコンテナにJuliaIDEのJunoと連携することも確認済みです．
  - See [Julia v 1.1.0 の Docker を拡張して Jupyter と Atom から利用できるようにしよう](https://qiita.com/SatoshiTerasaki/items/896c59dbe1432f926552) to learn more.
- VSCodeを使うとコンテナとの連携がしやすくなるようですのでそれに乗っかるというストラテジーでも良いと思います．