この記事
GitHubで管理しているRustプロジェクトにドキュメントをつけたくなることがあるかと思います。
ドキュメントはcargo doc --no-deps
などのコマンド一つで生成できるので、pushの際に自動で生成して公開できるとうれしいです。
自動で生成するのはGitHub Actionsを使うことができるし、公開するのはGitHub Pagesを使うことができるので、この二つを使うことで目的が達成できそうです。
しかし、これを達成するためのまとまった日本語の文書が見つからなかったので、備忘録も兼ねて残しておきたいと思います。
対象読者
- RustのプロジェクトをGitHubで管理している
- GitHub Actionsの役割がわかる
- GitHub Pagesの役割がわかる
結論(2022/08/11 追記)
GitHub Actionsのymlファイルだけ知りたい人用 https://github.com/hayas1/ghtest-project/blob/master/.github/workflows/rust.yml
(2022/08/11 上のymlファイルは少し古いです。)
GitHubがActionsからPagesへのデプロイをサポートしたので(まだベータ版ではありますが)、現在は次のようなymlファイルを書いておくとよいです。
GitHub Pages: Custom GitHub Actions Workflows (beta)
name: Rust
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
doc:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v3
- name: Run doc
run: cargo doc --no-deps
- name: Deploy
uses: actions/upload-pages-artifact@v1
with:
path: target/doc
deploy:
needs: doc
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
手順
準備
まずは、GitHubのリポジトリは適当に作っておいてください。ここではghtest-project
という名前で作成しています。
Rustのプロジェクトを作成し、GitHubへpushします。ここではghtest_project
というプロジェクト名で進めていきます。
cargo new --lib ghtest_project
cd $_
git add .
git commit -m "first commit"
git remote add origin https://github.com/[username]/ghtest-project.git
git push -u origin master
[username]
などと書いているところは適宜置き換えてください。
すでにリポジトリを作成している場合はここまでは関係ないです。
ドキュメントを書いた関数を作成
まずは、src/lib.rs
に簡単な引き算関数とドキュメントを書いていきます。
テストコードがcargoによって初めから作成されていますが、テストが通ったときのみドキュメントを生成するようにしたいので、今回は残しておきます。
//! ghtest_project
//! # Document
//! 自動でドキュメントを作成して公開するテストです。
/// a - b を計算します
/// # Panics
/// a < b の時、オーバーフローします
/// # Examples
/// ```
/// use crate::ghtest_project::sub;
/// let (a, b) = (3, 2);
/// assert_eq!(sub(a, b), 1);
/// ```
pub fn sub(a: u64, b: u64) -> u64 {
a - b
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
さて、この状態で、まずはローカルにドキュメントを作成してみます。
cargo doc --no-deps --open
とすることで、ドキュメントを生成し、ブラウザで開くことができます。(WSLを使っている場合は--open
がうまく効かず、ブラウザで起動できないかもしれません。そのときは、explorer.exe .
などして、target/doc/ghtest_project/index.html
をダブルクリックするなど)
このようなよく見るRustのドキュメントが生成されたのではないかと思います。
いまいち関数などがいい感じに表示されない場合は、可視性の設定の問題だと思います。**pub
**をmod
やfn
やstruct
やtrait
などに適切につけておいてください。
sub関数のページはこんな感じです。書いたドキュメントがちゃんと反映されています。
では、この状態でcommitし、pushしておきます。(ここからはcommitやpushのコマンドは特に明記しません。)
GitHub Actions を設定
次に、GitHub Actionsを設定します。上のタブの、Actionsをクリックします。
すると、一番上にRust用のワークフローのテンプレートがリコメンドされると思います。
それを選択します。
このワークフローは、デフォルトで、「pushかプルリクされたときに、ビルドとテストを行ってくれる」コマンドが記述してあります。
name: Rust
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
今回の目的は、テストが通ったときにドキュメントを自動で生成し、GitHub Pagesに公開することですので、このファイルを少し書き換えます。
name: Rust
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
CARGO_TERM_COLOR: always
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run tests
run: cargo test --verbose
doc:
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'push' || github.event.pull_request.merged == true
steps:
- uses: actions/checkout@v2
- name: Run doc
run: cargo doc --no-deps
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./target/doc/
先ほどのymlファイルに加えて、ドキュメント生成用のワークフローを追記しています。needs
を用いて、テストが完了したときのみ、そして、pushされたときと、マージされたときにのみドキュメントを作成するようにif
で条件を指定しています(プルリクが作られただけの時にドキュメントを作成してしまうと困るので)。 (ここはあまり洗練されていないかもしれません。ごめんなさい。)
また、GitHub Pagesは、gh-pages
というブランチを作成してデプロイするなどの手順がありますが、それらの設定はGitHub上で公開していただいているものを使うことができるようです(https://github.com/peaceiris/actions-gh-pages)。そのため、ドキュメントが出力されるディレクトリをpublish_dir
に指定するだけでよいです。
さて、ymlファイルが編集出来たら、適当に保存してコミットしておきましょう。ファイル名はそのままrust.yml
でいいかと思います。このときmasterにそのままコミットするか、新たにブランチを作ってマージする形でコミットするかを聞かれるかと思いますが、お好みの方でいいと思います。
GitHub Pages を見る
ここまでくると、先ほどymlファイルをいじったときのコミットですでにGitHub Actionsが走り、gh-pages
ブランチが作成されています(ただし、全てのテストが通っている場合に限る)。ブランチの一覧から存在を確認できるかと思います。
というわけで、さっそくindex.html
へアクセスしてみましょう。URLは、 https://[username].github.io/ghtest-project/ghtest_project/ です。[username]
とghtest_project
のところは適切なリポジトリ名へ変更してください。(GitHub Pagesは、ghtest-project(リポジトリ名)直下にindex.htmlがあると思っているので、自動で生成されるGitHub Pagesへのリンクでは404が発生すると思います。実際はさらに一つ下のghtest_project(クレート名)の場所にcargoによって生成されるので、一つ深くなることに注意が必要です。)
GitHub Pagesは少し反映が遅いので、いくらか待たないとアクセスできないかもしれません。あるいは、GitHubのSetting->Optionの下の方の「GitHub Pages」オプションのブランチがNoneになっているかもしれませんので、gh-pages
ブランチへ変更して保存してください。そしてもう一度GitHubからGitHub ActionsのRerunなどをすれば反映されるのではないかと思います。
それでもまだ反映されない場合は、一度gh-pages
ブランチの最も上の階層に、index.html
を作成する必要があるかもしれません。GitHubのページでAdd file
ボタンから新たにファイルを作成することができるので、gh-pages
ブランチへindex.html
を作成してください。ファイルの中身は、lib/index.html
へリダイレクトさせる内容を書いておきます(参考: https://users.rust-lang.org/t/whats-the-best-documentation-solution-other-than-docs-rs/16211/3)。これについても、ghtest_project
の場所は適切なパスへ書き換えておいてください。(ここで作成したindex.htmlは次のpushの際のビルドで自動的に消去されるので、関係ないとは思いますが、試した手順として念のため残しておきます)
<html>
<head>
<noscript><meta http-equiv="refresh" content="0; url=ghtest_project/index.html"></noscript>
</head>
<body onload="window.location = 'ghtest_project/index.html'">
<a href="ghtest_project/index.html">look here</a>
</body>
</html>
ここまですると、ドキュメントが表示されるのではないかと思います(重ねて、URLは https://[username].github.io/ghtest_project(リポジトリ名)/ghtest_project(クレート名)/ です)。
pushしてみる
最後に、本当にpushすると自動でドキュメントが更新されるか試してみます。
先ほど作成した引き算関数の上に足し算関数を定義して、pushしてみます。ついでにテストも書いておきました。
//! ghtest_project
//! # Document
//! 自動でドキュメントを作成して公開するテストです。
/// a + b を計算します
/// # Examples
/// ```
/// use crate::ghtest_project::add;
/// let (a, b) = (3, 2);
/// assert_eq!(add(a, b), 5);
/// ```
pub fn add(a: u64, b: u64) -> u64 {
a + b
}
/// a - b を計算します
/// # Panics
/// a < b の時、オーバーフローします
/// # Examples
/// ```
/// use crate::ghtest_project::sub;
/// let (a, b) = (3, 2);
/// assert_eq!(sub(a, b), 1);
/// ```
pub fn sub(a: u64, b: u64) -> u64 {
a - b
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn add_test() {
let (a, b) = (3, 2);
assert_eq!(add(a, b), 5);
}
#[test]
fn sub_test() {
let (a, b) = (3, 2);
assert_eq!(sub(a, b), 1);
}
}
さて、またcommitし、pushしてみます。
GitHub Actionsの動作過程は、リポジトリのトップ画面のコードのところの黄色い○のアイコンから確認できます。テストが通った後、ドキュメントの生成が始まる過程を見るのも面白いと思います。(なお、全て終了するとこのアイコンは緑のチェックマークになります。)
先ほどのアイコンが緑のチェックマークになったのを確認したら、もう一度GitHub Pagesのページへ飛んでみます。
先ほど追加したadd関数が追加されています!
参考までに今回使用したリポジトリの、GitHub Pagesへのリンクを貼っておきます。https://hayas1.github.io/ghtest-project/ghtest_project/
(そのうち公開を停止するかもしれません、ご了承ください)
以上です。お疲れ様でした。
最後に
どこかおかしかったり、もっといいymlファイルの書き方があるなどがありましたら、コメントなどよろしくお願いします。