はじめに
Rustでコードを書いて、WASMにしてnpmのパッケージにするとなると、wasm-packを使うのが一般的らしい。
ところがいろいろなツールを使うために自動テスト&デプロイには一工夫がいる。
最初の試み(結局やめた): Docker + Circle CIでの自動化
最初に自動化を試みたころ、ちょうどDockerの勉強をしていたので、Dockerが使いたかった。あとCircle CIを使い始めた頃だったのでそれを選んだ。
Docker Imageの作成
最初の試み(失敗): Alpine Linuxベースで作る
FROM alpine:3.10
RUN apk add --no-cache zlib-dev openssl-dev git bash rust cargo nodejs npm && \
npm update -g npm && \
cargo install wasm-pack && \
# https://rustwasm.github.io/wasm-pack/book/prerequisites/non-rustup-setups.html
wget https://static.rust-lang.org/dist/rust-std-1.34.2-wasm32-unknown-unknown.tar.gz && \
tar -xf rust-std-1.34.2-wasm32-unknown-unknown.tar.gz && \
mv rust-std-1.34.2-wasm32-unknown-unknown/rust-std-wasm32-unknown-unknown/lib/rustlib/wasm32-unknown-unknown /usr/lib/rustlib/ && \
rm -r rust-std-1.34.2-wasm32-unknown-unknown && rm rust-std-1.34.2-wasm32-unknown-unknown.tar.gz
# INFO 2019-09-09T16:55:21Z: wasm_pack::command: Running build command...
# INFO 2019-09-09T16:55:21Z: wasm_pack::command::build: Checking rustc version...
# INFO 2019-09-09T16:55:21Z: wasm_pack::command::build: rustc version is 34.
# INFO 2019-09-09T16:55:21Z: wasm_pack::command::build: Checking crate configuration...
# INFO 2019-09-09T16:55:21Z: wasm_pack::command::build: Crate is correctly configured.
# INFO 2019-09-09T16:55:21Z: wasm_pack::command::build: Checking for wasm-target...
# [INFO]: Checking for the Wasm target...
# INFO 2019-09-09T16:55:21Z: wasm_pack::build::wasm_target: Looking for wasm32-unknown-unknown in "/usr/lib/rustlib"
# INFO 2019-09-09T16:55:21Z: wasm_pack::build::wasm_target: Found wasm32-unknown-unknown in "/usr/lib/rustlib"
# INFO 2019-09-09T16:55:21Z: wasm_pack::command::build: Checking for wasm-target was successful.
# INFO 2019-09-09T16:55:21Z: wasm_pack::command::build: Building wasm...
# [INFO]: Compiling to Wasm...
# INFO 2019-09-09T16:55:21Z: wasm_pack::child: Running "cargo" "build" "--lib" "--target" "wasm32-unknown-unknown"
# [2019-09-09T16:55:21Z INFO cargo::util::rustc] failed to read rustc info cache: failed to read `/markdown_img_url_editor/markdown_img_url_editor_rust/target/.rustc_info.json`
# [2019-09-09T16:55:21Z INFO cargo::util::rustc] rustc info cache miss
# [2019-09-09T16:55:21Z INFO cargo::util::rustc] rustc info cache miss
# [2019-09-09T16:55:21Z INFO cargo::util::rustc] rustc info cache miss
# [2019-09-09T16:55:21Z INFO cargo::util::rustc] rustc info cache miss
# [2019-09-09T16:55:21Z WARN cargo::util::rustc] failed to update rustc info cache: failed to write `/markdown_img_url_editor/markdown_img_url_editor_rust/target/.rustc_info.json`
# error: failed to run `rustc` to learn about target-specific information
# Caused by:
# process didn't exit successfully: `rustc - --crate-name ___ --print=file-names --target wasm32-unknown-unknown --crate-type bin --crate-type rlib --crate-type dylib --crate-type cdylib --crate-type staticlib --crate-type proc-macro` (exit code: 1)
# --- stderr
# error: Could not create LLVM TargetMachine for triple: wasm32-unknown-unknown: No available targets are compatible with triple "wasm32-unknown-unknown"
ENV PATH $PATH:/root/.cargo/bin
上のようなDocker Fileを作ったのだが、コメントで書いたようなエラーが出てうまくいかなかった
次の試み: OfficialのRustイメージベース
FROM rust
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - && apt-get install -y nodejs && rm -rf /var/lib/apt/lists/* && \
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
これは一応うまく行った。
Cirlce CIの設定
version: 2.1
executors:
default:
docker:
- image: yumetodo/buildcontainers:rust-latest-wasm-lts
working_directory: ~/repo
commands:
tool_install:
steps:
- run: npm i -g can-npm-publish
cargo_restore_cache:
steps:
- run:
name: Calculate dependencies
command: cargo generate-lockfile
working_directory: markdown_img_url_editor_rust
- restore_cache:
keys:
- v4-cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }}
cargo_save_cache:
steps:
- save_cache:
paths:
- /usr/local/cargo/registry
- target/debug/.fingerprint
- target/debug/build
- target/debug/deps
- target/release/.fingerprint
- target/release/build
- target/release/deps
key: v4-cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }}
jobs:
test:
executor: default
steps:
- checkout
- cargo_restore_cache
- run: cargo test
- run: wasm-pack build
- cargo_save_cache
publish:
executor: default
steps:
- tool_install
- checkout
- run: wasm-pack build --release --target nodejs
- run: echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} > ~/.npmrc
- run:
command: |
if can-npm-publish --verbose pkg; then
wasm-pack publish
else
echo "publish skipped"
fi
workflows:
version: 2
publishflow:
jobs:
- test
- publish:
context: npm
requires:
- test
filters:
tags:
only: /^v.*/
さっき作ったDocker Imageを指定してこんな感じに設定したらうまく動いた。
次の試み: Github Actionsをつかう
しかしよく考えてほしい。node.jsは頻繁に新しいバージョンがでるし、rustもそれなりにバージョンアップが来る。wasm-packだって更新が来る。そのたびにImage作って更新していくと考えるとかなりだるい。
そもそもDockerを使うべきじゃなかった気がしてくる。
そこで目をつけたのがGithub Actionsだ。これはUbuntuの上で走る(いや他のも選べるし、更にその上でDocker動かすとかもできるけど)。
ちょっとまえにcpprefjp(C++のリファレンスサイト)にかんたんなチェックをするCIをGithub Actionsで組んだばかりだったので、勝手がわかってるのも大きい。
https://github.com/cpprefjp/site/pull/737
name: Test and Release
on:
[push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Cache cargo registry
uses: actions/cache@v1
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo index
uses: actions/cache@v1
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
- name: Cache cargo build
uses: actions/cache@v1
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
- name: Run tests
run: cargo test --verbose
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: 12.x
registry-url: 'https://registry.npmjs.org'
- name: install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- run: wasm-pack build --release --target nodejs
- name: wasm-pack publish when possible
run: |
if npx can-npm-publish --verbose pkg; then
wasm-pack publish
else
echo "publish skipped"
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Cargoのキャッシュ設定は
https://github.com/actions/cache/blob/master/examples.md#rust---cargo
のものを拝借した。
Github ActionsのRustの設定例
https://github.com/actions/starter-workflows/blob/e5a3a0e11268f84ad0ff6569a47e197cc8e1f758/ci/rust.yml
を見てみたところ、どうも何もしなくてもcargoは使えるらしい。どのバージョンとかは面倒くさいので調べてないが、まあ動いているのでいい。
npm publish
する時
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
のようにするのだが、wasm-pack publish
する先行事例が見つからなくて不安だった。結果動いたのでよい。
あと、PRからのビルドのときはpublish周りはいらないので
https://github.com/yumetodo/markdown_img_url_editor_rust/blob/aeb43c0d46439c24c665848183cece9599c71695/.github/workflows/test.yml#L1
省略版を作った。
ところでsecrets.NPM_TOKEN
ってPRから見えたりはしないですよね?確認してないけど。
成果
に上がっている。
ちなみにこのパッケージは何かというと
というような依存関係になっている。