🦕

Deno製タスクランナーVelociraptorの使い方と設定の紹介

2021/07/15に公開

以前、Denoの開発テンプレートを作成しました。

https://zenn.dev/kawarimidoll/articles/1c48c097020cbc

このときに出会ったVelociraptorというタスクランナーについて、自分の知識の整理も兼ねて、ツール自体の説明および現在の設定について書きます。

こちらのBookで知りました。
https://zenn.dev/uki00a/books/effective-deno/viewer/task-runner

Velociraptorの説明

https://velociraptor.run/

本記事執筆時の最新バージョンは1.0.1です。

概要

Velociraptorは、Deno製、Deno用のタスクランナーです。
Denoのコマンドの管理および実行を簡単にしてくれます。

denoはその権限管理システムにより、許可していないリソースへのアクセスはできないようになっています。これは逆に、実行時にdeno run --allow-net --allow-write main.tsのように毎回権限許可を行う必要があるということです。

正直煩雑なので、Velociraptorを知る前は以下のようなシェルスクリプトを作っていました。

run.sh
#!/bin/bash
deno run --allow-net --allow-write main.ts

しかし、これだけならともかく、sub.tsも実行したいとか、同じ権限でテストもやりたいとか、他の要求が出てくると、実行コマンドをシェルスクリプトに押し込む方法では管理が大変になります。

Velociraptorでは、これらを単一の設定ファイルに書き込み、vrコマンドで簡単に実行できるようにしてくれます。
要するに、単純にDeno用プログラムの実行が楽になります。
また、GitフックやGitHub Actionsでのワークフローにも対応しているので、いろいろ応用が効きます。

導入

deno installを使ってインストールします。

deno.landからインストールする場合はこちら:

❯ deno install -qAn vr https://deno.land/x/velociraptor@1.0.1/cli.ts

nest.landからインストールする場合はこちら:

❯ deno install -qAn vr https://x.nest.land/velociraptor@1.0.1/cli.ts

deno installのインストール先(デフォルトは~/.deno/bin)にvrという実行ファイルがインストールされます。
中身はこんな感じです。

vr
#!/bin/sh
# generated by deno install
exec deno run --allow-read --allow-write --allow-net --allow-env --allow-run --allow-plugin --allow-hrtime --quiet 'https://deno.land/x/velociraptor@1.0.1/cli.ts' "$@"

なお、実行ファイル名はインストール時の-n vrオプションで設定しているだけなので、自由に変更できます。ただ、ドキュメントはvrという名前であることを前提に書かれているので、基本的にはvrでインストールしたほうが良いでしょう。

また、公式ページのインストールスクリプトを使った場合は最新のものを入手できると思いますが、こちらの記事など、公式以外のものを使用した場合は、インストール後にupgradeをかけておくと安心かと思います。

❯ vr --version
1.0.1

❯ vr upgrade
info: Velociraptor is already up-to-date

シェル補完も設定しておくのがおすすめです。Zsh以外のシェルに関しては公式ページをご確認ください。

~/.zshrc
source <(vr completions zsh)

設定

Denoプロジェクトディレクトリにscripts.<EXT>またはvelociraptor.<EXT>という名前のファイルを設置します。拡張子はyml yaml json tsが使えます。

例を載せましょう。公式ページのものです。

velociraptor.yml
scripts:
  start: deno run --allow-net server.ts
  test: deno test --allow-net server_test.ts
velociraptor.json
{
  "scripts": {
    "start": "deno run --allow-net server.ts",
    "test": "deno test --allow-net server_test.ts"
  }
}
velociraptor.ts
export default {
  scripts: {
    start: "deno run --allow-net server.ts",
    test: "deno test --allow-net server_test.ts",
  },
};

どれでも動作はするのですが、ファイル名はscriptsよりvelociraptorのほうが専用ファイルだとわかりやすいと思います。また、個人的にはymlの記述が好みです。
ということで、以下ではvelociraptor.ymlで統一していきます。

使用

vr [スクリプト名]velociraptor.ymlに定義したスクリプトを実行できます。本来はvr run [スクリプト名]らしいのですが、このrunサブコマンドは省略できるので、明示的に使われることはまず無いでしょう。

❯ # equivalent
❯ vr run start
❯ vr start

また、vrを引数無しで実行すると、定義されているスクリプトの一覧が表示されます。
さらに、引数の有無に関わらず、プロジェクト内でvrを実行したときに、velociraptor.ymlで定義されたGitフックが設定されます。
共同開発者に環境を統一して貰う場合など、git clone後にとりあえずvrを実行してもらうと良いと思います。

現在使用している設定

velociraptor.ymlの設定を紹介します。

velociraptor.yml
allow:
  # - write
  # - read
  # - net
  - env

envFile:
  - .env

scripts:
  start:
    desc: Runs main script
    cmd: main.ts

  dev:
    desc: Starts local server
    cmd: deployctl run --libs="" --watch --env=.env server.ts

  lint:
    cmd: deno lint
    desc: Runs lint

  fmt:
    cmd: deno fmt
    desc: Runs format

  pre-commit:
    cmd: |
      FILES=$(git diff --staged --name-only --diff-filter=ACMR "*.ts")
          [ -z "$FILES" ] && exit 0
          echo "$FILES" | xargs deno lint
          echo "$FILES" | xargs deno fmt
          # echo "$FILES" | xargs git add
    desc: Lints and formats staged files
    gitHook: pre-commit

  test:
    cmd: deno test --reload --coverage=cov_profile
    desc: Runs the tests
    gitHook: pre-push

  cov:
    cmd: deno coverage cov_profile
    desc: Shows uncovered lists

  ci:
    cmd:
      - deno lint
      - deno fmt --check
      - deno test --reload
    desc: Runs lint, check format and test

fmt-pre-commitcmd内部がインデントされているのは、vrを実行したときの説明表示を良い感じにするためです。

❯ vr

  🦖 Available scripts

    • start
    Runs main script
    $ main.ts

    • dev
    Starts local server
    $ deployctl run --libs="" --watch --env=.env server.ts

    • lint
    Runs lint
    $ deno lint

    • fmt
    Runs format
    $ deno fmt

    • pre-commit
    Lints and formats staged files
    Runs at pre-commit
    $ FILES=$(git diff --staged --name-only --diff-filter=ACMR "*.ts")
    [ -z "$FILES" ] && exit 0
    echo "$FILES" | xargs deno lint
    echo "$FILES" | xargs deno fmt
    # echo "$FILES" | xargs git add

    • test
    Runs the tests
    Runs at pre-push
    $ deno test --reload --coverage=cov_profile

    • cov
    Shows uncovered lists
    $ deno coverage cov_profile

    • ci
    Runs lint, check format and test
    $ deno lint, deno fmt --check, deno test --reload

  To run a script pass its name as the first argument to the vr command:

  $ vr start

  Any additional arguments will be passed to the script.

以下、各項目について解説していきます。

allow

全体で許可するパーミッションを設定します。
とりあえずwrite read env netをコメントの形で用意しておいて、必要になったらコメントアウトを外すようにすると楽です。

以下のように引数を追加することもできます。

velociraptor.yml
allow:
  - write=output.json
  - net=example.com

また、全体には許可したくない場合、スクリプトごとにパーミッションを設定することもできます。

velociraptor.yml
scripts:
  start:
    desc: Runs main script
    cmd: main.ts
    allow:
      - read

envFile

環境変数ファイルの読み込みです。
設定した環境変数はDeno.env.get()で取得できます。

start

メインスクリプトの実行です。Velociraptorでは、cmdにファイル名のみを記載すると、自動的にdeno runの対象として解釈されます。

startmain.tsという名前はさておき、実行の場合はこのように書くのだな、と覚えていただければ良いと思います。

dev

Deno Deployローカル実行のdeployctl用の記述です。

こちらも名前は何でも構いません。

オプションの設定は以前の記事で解説しているので、詳細は割愛します。
https://zenn.dev/kawarimidoll/articles/efed8ada433f24
https://zenn.dev/kawarimidoll/articles/752f74860d0d78

lint

静的解析を実行します。まあdeno lintvr lintになるだけなので、別にこの設定がなくてもそれほど変わらないのですが。

pre-commitフックを設定すれば、問題のあるコードがあったときにコミットを停止できます。
ただ、普通に設定してしまうと以下の点が気になります。

  • コミットするたびにプロジェクト全体を解析することになり、時間も処理能力も無駄
  • まだコミットするつもりのない作業中のコードまで解析対象となってしまい、コミット停止されてしまう

ということで、コミット時の解析はpre-commitスクリプトで別に定義しています。

fmt

フォーマットを実行します。こちらもlintスクリプトと同じく、deno fmtvr fmtになるだけです。

これにpre-commitフックを設定することでコミット時に自動フォーマットできます。
ただしこの場合、フォーマットはされるのですが、 フォーマットされた結果はそのコミットに乗りません。

pre-commit

Velociraptor公式のscripts.ymlを参考にしたものです。
https://github.com/jurassiscripts/velociraptor/blob/main/scripts.yml

ステージングされたファイルのみを対象にdeno lintおよびdeno fmtをかけます。
参考元ではecho "$FILES" | git addされているので、フォーマットされた結果をコミットに含めることができるのですが、この場合、対象ファイルは必ず全体がステージングされることになります。

個人的には、同一ファイル内の変更でもコミットを分けたい場合が結構あります[1]
ファイルの一部のみをコミットする選択肢がなくなってしまうのは不便なので、自ステージングは動作しないようにしています。

もしコミット後にフォーマットされたファイルが残った場合は、手動でgit addgit amendを行い、指定のコミットにまとめるようにしています。

test

テストを実行します。この際、--reloadオプションで依存関係のリロードを行い、--coverageオプションでcoverage profileを生成します。
https://deno.land/manual@v1.12.0/testing/coverage

また、pre-pushフックにより、Push前に実行されるようにしています。

このあたりは場合によって調整すると良いでしょう。

cov

vr testで生成したcoverage profileを表示します。

ci

リントとフォーマットとテストを実行します。
こちらはその名の通りCIとして実行されることを想定しているので、fmtスクリプトと違ってdeno fmtcheckオプションを付けていたり、deno test--coverageオプションを抜いていたりします。

CIでの使用

前述のvr ciをCIで使う例を紹介します。
以下はGitHub Actionsのワークフローファイルの例です。例と言ってもほとんど内容は無いのですが。

.github/workflows/cil.yml
name: ci

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - uses: denoland/setup-deno@v1
      - uses: jurassiscripts/setup-velociraptor@v1
      - run: VR_HOOKS=false vr ci

ブランチをチェックアウトして、DenoとVelociraptorを準備して、CIを実行するというだけのシンプルな構成です。
この際、実行時に環境変数VR_HOOKSfalseを設定し、Gitフックが設定されないようにしています。
https://velociraptor.run/docs/git-hooks/#skipping-hooks

.envファイルを使用する場合は、スクリプトの中で生成します。

.github/workflows/cil.yml
  name: ci

  on: [push, pull_request]

  jobs:
    test:
      runs-on: ubuntu-latest
      steps:
        - uses: actions/checkout@master
        - uses: denoland/setup-deno@v1
        - uses: jurassiscripts/setup-velociraptor@v1
+       - name: Create env file
+         run: |
+           touch .env
+           echo SECRET_TOKEN=${{ secrets.SECRET_TOKEN }} >> .env
        - run: VR_HOOKS=false vr ci

まとめ

Velociraptorを導入することで、Denoプログラムの実行が簡単になり、開発体験が向上します。
解析・フォーマットの方法も含めて管理できるので、チーム開発でも効果を発揮するでしょう。

こちらの設定は自作のテンプレートリポジトリで動いています。
https://github.com/kawarimidoll/deno-dev-template

ちなみに、ヴェロキラプトルというと映画「ジュラシック・パーク」に登場したものが有名ですが、あれはディノニクスがモデルらしいです。
https://ja.wikipedia.org/wiki/ヴェロキラプトル

脚注
  1. たいてい一気に作業したあとでコミット粒度を分けたほうが良いことに気づく ↩︎

Discussion