のぴぴのメモ

自分用のLinuxとかの技術メモ

gitのpull reqやpushで更新があったディレクトリを抽出しJOSNの配列にするシェル芸

やりたいこと

  • system毎にディレクトリが分かれているterraformがあり(下記イメージ)、パイプラインで更新があったプロジェクトのディレクトリを判別してterraformを実行したい。
  • 具体的には、git diffを使って差分があるディレクトリを抽出し、それをJOSNの配列にしたい。
  • 差分は、mainブランチとの差分で、1コミット分の差分抽出でOK
  • シェルで実現したい
.
├── README.md
├── modules
│   ├── network
│   ├── resource
│   └── security
└── projects
    ├── system-a
    │   ├── backend.tf
    │   ├── data.tf
    │   ├── local.tf
    │   ├── main.tf
    │   ├── provider.tf
    │   └── terraform.tf
    ├── system-b
    └── system-c

やりかた

mainへのpull requestの場合のmainコミットとの差分抽出

TARGET_BRANCH=main
git fetch --depth 1 origin ${TARGET_BRANCH}  > /dev/null 2>&1
git diff  ${TARGET_BRANCH} HEAD --name-only -- 'projects/' | \
  sed 's:\(^projects/[^/]*\)*.*$:\1:' | \
  sort | uniq | \
  jq -scR 'split("\n") | .[:-1]';

push時の一つ前のコミットとの差分抽出

TARGET_BRANCH=main
git fetch --depth 2 origin ${TARGET_BRANCH}  > /dev/null 2>&1
git diff HEAD^ HEAD --name-only -- 'projects/' | \
  sed 's:\(^projects/[^/]*\)*.*$:\1:' | \
  sort | uniq | \
  jq -scR 'split("\n") | .[:-1]';

実行例

TARGET_BRANCH=main
git fetch --depth 1 origin ${TARGET_BRANCH}  > /dev/null 2>&1
git diff  ${TARGET_BRANCH} HEAD --name-only -- 'projects/' | \
  sed 's:\(^projects/[^/]*\)*.*$:\1:' | \
  sort | uniq | \
  jq -scR 'split("\n") | .[:-1]';
["projects/system-a","projects/system-b","projects/system-c"]

解説

  • git fetchgit diff
TARGET_BRANCH=main
git fetch --depth 1 origin ${TARGET_BRANCH}  > /dev/null 2>&1
git diff  ${TARGET_BRANCH} HEAD --name-only -- 'projects/' 

projects/system-a/backend.tf
projects/system-a/data.tf
projects/system-a/local.tf
projects/system-a/main.tf
projects/system-a/provider.tf
projects/system-b/Makefile
projects/system-b/backend.tf
projects/system-c/dummy
  • sed 's:\(^projects/[^/]*\)*.*$:\1:' |
    • sedでprojects直下のフォルダまでのパスまでだけ抽出しています。
    • sedの書き方は、こちらを参照ください
    • /projects/xxxxxのパスまで絞り込めますが、この段階では同じディレクトリが重複した状態になります。
projects/system-a
projects/system-a
projects/system-a
projects/system-a
projects/system-a
projects/system-b
projects/system-b
projects/system-c
  • /sort | uniq/
    • uniqコマンドで重複している行を削除します。uniqの前提としてソートされている必要があるため、あらかじめsortコマンドで行をソートします。
    • ここまでの実行結果
projects/system-a
projects/system-b
projects/system-c
  • jq -scR 'split("\n") | .[:-1]'
    • jqコマンドでJSONの配列に変換しています。