🐼

denoプロジェクトの依存は積極的に更新していきたい

2024/02/05に公開

悩み

一般的なVimmerはDenoを使った開発プロジェクトが増えがちです。
なぜならdenops.vimを使ったプラグイン開発はVimmerの義務です。
Vimmer、あなたはdenops.vimプラグイン開発者ですか?ZAP ZAP ZAP

やがて増えゆくプロジェクト、増え続ける依存。
見たくないから見ない。気がついても更新しない。Dependabotに言われてもマージしない。そして破局を迎える。

udd便利

denoの依存を、一括で更新するuddというツールが便利です。

$ udd ./**/*.ts

とでもしてやれば、配下の.tsファイルの依存を更新してくれます。
しかし、プロジェクトが増えてくるとこれを1つ1つのプロジェクトに実行するのも骨が折れる物です。

スクリプトしよう

困ったら、スクリプトでも書けば良いんです。
私の例(zsh)を貼っておきますが、あくまでも私の例です。次節で少し流れと、肝心な部分を説明します。

function _update_deno_dependencies() {
  pushd "$1"
  _update_deno_dependencies_core "$1"
  ret=$?
  popd
  return $ret
}

function _update_deno_dependencies_core() {
  local dir="$1"
  echo "\e[1m\e[31mUpdating $dir...\e[0m"
  if [ -n "$(git status --porcelain)" ]; then
    echo "\e[31mThere're changes in $dir\e[0m"
    return
  fi
  echo "Pulling $dir..."
  git pull
  if [ -n "$(git status --porcelain)" ]; then
    echo "\e[31mThere're changes in $dir\e[0m"
    return
  fi
  echo "No dirty changes in $dir"
  if ! NO_COLOR=1 udd ./**/*.ts; then
    echo "\e[31mFailed to update dependencies in $dir\e[0m"
    return
  fi
  if [ -z "$(git status --porcelain)" ]; then
    echo "There's no update in $dir"
    return
  fi
  if ! NO_COLOR=1 deno cache ./**/*.ts; then
    echo "\e[31mFailed to cache in $dir\e[0m"
    return
  fi
  if ! NO_COLOR=1 deno task check; then
    echo "\e[31mThere're problems in $dir\e[0m"
    return
  fi
  if ! NO_COLOR=1 deno task lint; then
    echo "\e[31mThere're lints in $dir\e[0m"
    return
  fi
  if [[ -n ./**/*_test.ts(#qN) ]]; then
    if ! NO_COLOR=1 deno task test; then
      echo "\e[31mFailed to test $dir\e[0m"
      return
    fi
  fi
  git --no-pager diff .
  read "YN?Process? (y/n/q):"
  case "${YN}" in
    y|Y)
      echo "do"
      ;;
    n|N)
      echo "skip"
      git restore .
      return
      ;;
    q|Q)
      echo "quit"
      git restore .
      return 1
  esac
  if ! git add .; then
    echo "\e[31mFailed to stage changes in $dir\e[0m"
    return
  fi
  if ! git commit -m "Update dependencies"; then
    echo "\e[31mFailed to commit changes in $dir\e[0m"
    return
  fi
  if ! git push; then
    echo "\e[31mFailed to push changes in $dir\e[0m"
    return
  fi
}

function update_deno_dependencies() {
  # projectのあるディレクトリに移動する
  pushd ~/Projects/github.com/kyoh86

  # 各ddu-*のディレクトリの中で、dirtyでなければgit pullを実行する。
  # pullした時点でもdirtyでなければ、deno dependenciesの更新を実行する。
  if _update_deno_dependencies denops-util; then
    for dir in {ddu,denops}-*; do
      if [ -d "$dir" ]; then
        if ! _update_deno_dependencies "$dir"; then
          # quit
          break
        fi
      fi
    done
  fi

  git-statuses

  popd
}

流れ

このスクリプトでは、私のローカルにおかれたすべてのdeno製プロジェクト(名前がddu-またはdenops-で始まる)を順に巡って、次のような処理を行っています。

  • git dirtyでないことをチェック、dirtyだったらこのプロジェクトは処理しない
  • udd ./**/*.tsで依存関係を根こそぎ更新
  • git dirtyであることをチェック、更新がなければこのプロジェクトは処理しない
  • deno cacheを取得
  • deno check, lint, testを実行、問題ないことを確認
  • diffを表示してユーザーに(yes/no/quit)で問う
  • git add, commit, pushを実行

要は「ローカルのプロジェクトの依存関係を更新して、更新されたならテストして、テストが通ればプッシュ」ということですね。

肝としては、deno check, lint, testはdeno.jsoncにtask化しており、必要なチェックをパターン化してある点です。

  • checkの前にgenerateを必要とする場合がある
  • linterとしてdeno lint以外の何かを回すことがある
  • プロジェクトによってはtestには--allow-*などを指定する必要がある

もちろん、deno task以外の方法でもいくらでも回避できますが、画一的な処理のためには必要でしょう。

改善点

現状「自分のローカルにあるプロジェクトを横断する」という形を取っていますが、
自分のローカルにあるプロジェクトの状態なんぞ常に安全とは限りませんし、ローカルに常にfetchしておくのも億劫です。
本来ならGitHubのリポジトリにlang=typescriptでクエリをかけて、cloneして以下同文…とでもするべきでしょう。

まあ、雑にやればこんなこともできるよ、という一例として紹介させていただいたので、自分のスタイルに合った何かを作ってみると良いかもしれません。

Discussion