2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[ node.js + Git ] 〇〇するまえに✖︎✖︎する

Last updated at Posted at 2023-05-28

先に結論だけ

Gitnpmスクリプトには、コマンドの実行前後に割り込む仕組みが用意されています。この仕組みをLinterやテスティングフレームワークと組み合わせると、ヒューマンエラーと作業工数を減らせます。

はじめに

この記事はGitとnpmスクリプトにおける、コマンドに割り込む仕組みについて記録、共有するためのものです。

対象とする読者

  • Gitを使ったことがある。
  • node.jsを使ったことがある。
  • 開発フローでのヒューマンエラーを減らしたい。

想定する環境

  • git version 2.40.1
  • npm 9.5.0

対象となるパッケージのメジャーバージョンが変わると、記事の内容がそのまま適用できないかもしれません。記事を読む前に、お手元の環境をご確認ください。

Git

Gitには、Gitフックという仕組みがあります。

Gitフックとは

Gitフックとは、gitコマンドの前後に任意のコマンドを割り込ませるための仕組みです。一般的なプロジェクトでは.git/hooksディレクトリにフック用スクリプトを配置します。

node.jsでフックを作成/管理する

GitフックはGit管理外の.gitディレクトリに配置されるため、リポジトリの参加者には共有されません。Gitフックを共有するには、別のディレクトリにスクリプトを配置しなければいけません。

また、Gitフックの実行環境はシェルです。そのため、開発メンバーの環境によってはフックが動作しないことがあります。

これらの問題を解消するため、いくつかのnpmモジュールが公開されています。この記事では、huskyを利用してフックを作成/管理します。

preフック

pre-で始まるフックは、対応するgitコマンドの前に実行されます。preフックが正常に終了しなければ、続くコマンドは実行前にキャンセルされます。

pre-commit

pre-commitフックは、ブランチへコミットする前に実行されます。

commit前にlint/コードフォーマッターを自動実行する

コミット前にlintやコードフォーマッターを自動実行することで、表記揺れをなくしコードの品質を維持できます。例として、prettierpretty-quickを使ってコードフォーマッターを自動実行する方法を紹介します。

▼.husky/pre-commit

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx pretty-quick --staged

pre-push

pre-pushフックは、リモートリポジトリへpushする前に実行されます。

push前にテストを自動実行する

push時に、テストを通過することを強制します。

▼.husky/pre-push

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm test

testコマンドが正常に終了しないと、pushは中断されます。

デフォルトブランチへのpushを禁止する

ブランチの切り替えを忘れて、mainブランチへpushしてしまうことがあります。このようなヒューマンエラーを防ぐため、特定の名前のブランチへのpushを禁止します。

具体的な実装方法については、上記の記事を参照してください。みなさまのプロジェクトのブランチ運用ルールに合わせて、ブランチ名などの条件を変更してください。

GitHubのブランチ保護ルール

GitHubにはブランチ保護ルールという機能があります。この機能を使うと、特定のブランチに対する操作を制限できます。

テストの自動実行やpushの禁止は、Gitフックとブランチ保護ルールの両方で実現できます。どちらを採用するかは開発環境 / 実行環境やメンバーの構成によって変化しますので、プロジェクトごとに検討が必要です。

node.js

node.jsのnpmコマンドにも、Gitフックとよく似た割り込み機能があります。npmコマンドの割り込みは、package.jsonscriptsフィールドで定義します。

pre/post修飾子

▼package.json

{
  "scripts": {
    "precompress": "{{ executes BEFORE the `compress` script }}",
    "compress": "{{ run command to compress files }}",
    "postcompress": "{{ executes AFTER `compress` script }}"
  }
}

npmスクリプトの名前にpreまたはpostを付けると、対応するコマンドの前後に処理が割り込まれます。自作したスクリプトと組み込みのコマンドの両方に対応しています。

preversion

例として、npm versionコマンドの前に割り込むpreversionスクリプトを作成します。

▼package.json

{
  "scripts": {
    "preversion": "npm test"
  }
}

テストに成功しなければ、versionコマンドは中断され、タグ付けもされません。

npmコマンドとGitフックが競合する場合

npm versionコマンドは、内部的にGitのコミットとタグ作成を実行します。そのため、versionコマンドを実行すると同時にGitフックも実行されます。

preversionコマンドとpre-commitフックが競合する場合、versionコマンドのオプションでpre-commitフックを無効化できます。

npm version --no-commit-hooks patch
npm version --commit-hooks false patch

この2つのオプションは同じ意味になります。npmはno-接頭辞を付けたbooleanオプションをfalseとして処理します。

個人的な感想

フックの導入はヒューマンエラーの削減に大きな効果があります。継続的なメンテナンスが必要なプロジェクトでは積極的に導入しましょう。

一方、動作環境に影響されるためフック自体のメンテナンスが必要になります。この点を踏まえて、ローカルでフックを動作させるか、動作環境に差異が出ないGitHub ActionsのようなCI/CD環境を利用するかを検討する必要があります。

以上、ありがとうございました。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?