bun.lockbのコンフリクトをどうにかしたかった話

## はじめに
`bun`のバージョンが`1.0.0`になりましたね！！🎉（3ヶ月前）

最近よくbunをpackage managerとして使ってるのですがいかんせんコンフリクトがめんどくさすぎてどうにかならないかなぁと思って今回どうにかしたかった話をします。


## 目的
最終的な目標は`bun.lockb`のコンフリクトをローカルでいじらずにgithub actionsでどうにかすること。

## 現状の課題
githubのプルリクエストにてコンフリクトが起きます
その場合ローカルでマージしてpush
またはブラウザ上のエディタでコンフリクトを解消する必要があります。
いかんせん前者は必要な工程がチョット多くてめんどくさい(そこまででもない)のでどうにかブラウザ上のエディタでどうにかしたいです。

しかしブラウザ上のエディタではバイナリデータのコンフリクトは解消できません(以下のような表示が出る。)
![スクリーンショット 2024-01-01 21.37.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230849/d75e8a5b-87ed-9819-43ff-1fa6a6ec2e50.png)

こうなるともうブラウザエディタ上ではコンフリクトは解消できません
ローカルでマージ元とマージ先を更新してマージ元にマージ先をマージして起きたコンフリクトをローカルで解消するしかありません。
正直lockファイルのためにこれをやるのはめんどくさいです
というのも`bun.lockb`のコンフリクトは`bun i`を再実行すれば`package.json`を元に再生成されるのでそこまで必要な操作もないんです
てことでこれをいい感じにしていきます。

## アプローチ
github actionsを使って色々コネコネします。
自動でコンフリクト解消してもいいのですが気づかない間に変な変更されるのも嫌なのでworkflowのトリガーは手動にします。
先に作成したymlを貼ります

```yml:resolve_lock_conflict.yml
name: Resolve Lock Conflict

on:
    workflow_dispatch:

jobs:
    conflict-check:
        runs-on: ubuntu-latest
        steps:
            - name: Checkout base branch
              uses: actions/checkout@v2

            - name: check pr created
              run: |
                  if gh pr list --head ${{ github.ref_name }} | grep -q 'No open pull requests found'; then
                      echo "No open pull requests found"
                      exit 1
                  else
                      echo "Open pull requests found"
                      echo "BASE_REF_NAME=$(gh pr view ${{ github.ref_name }} --json baseRefName -q '.baseRefName')"
                      echo "BASE_REF_NAME=$(gh pr view ${{ github.ref_name }} --json baseRefName -q '.baseRefName')" >> $GITHUB_ENV
                  fi
              env:
                  GH_TOKEN: ${{ github.token }}
            - name: merge base branch
              run: |
                  git config user.name 'GitHub Actions'
                  git config user.email 'actions@github.com'
                  git pull --allow-unrelated-histories origin ${{ env.BASE_REF_NAME }} --no-commit --no-ff || true

              shell: bash
            - name: Check bun lock conflict
              run: |
                  if git diff --name-only --diff-filter=U | grep 'package.json'; then
                    echo "package.json conflict found. please resolve package.json conflict"
                    exit 1
                  fi
                  if git diff --name-only --diff-filter=U | grep 'bun.lockb'; then
                    echo "IS_CONFLICT=true" >> $GITHUB_ENV
                  else
                    echo "IS_CONFLICT=false" >> $GITHUB_ENV
                  fi

            - name: setup bun
              if: env.IS_CONFLICT == 'true'
              uses: oven-sh/setup-bun@v1

            - name: resolve conflict
              if: env.IS_CONFLICT == 'true'
              run: |
                  rm -rf bun.lockb
                  bun install
                  git add bun.lockb
                  git commit -m "resolve conflict"
                  git push
              shell: bash
```

### ステップ1 PRチェック
まず最初にPRが作られているかどうかのチェックを行います(PRが作られていなければそもそもどのブランチとコンフリクトを起こしているのかわからないため)

まず`gh`コマンドでマージ元が指定されたブランチのPRを探します
PRが見つからなかった場合exitします。
PRが見つかった場合は環境変数にPRのマージ先のブランチを保持しておきます

```yml
- name: check pr created
  run: |
      if gh pr list --head ${{ github.ref_name }} | grep -q 'No open pull requests found'; then
          echo "No open pull requests found"
          exit 1
      else
          echo "Open pull requests found"
          echo "BASE_REF_NAME=$(gh pr view ${{ github.ref_name }} --json baseRefName -q '.baseRefName')" >> $GITHUB_ENV
      fi
  env:
      GH_TOKEN: ${{ github.token }}
```

## ステップ2 ローカルマージ
次にチェックアウトしたブランチでマージ先を取り込みます。
この時`--no-commit`オプションをつけることでコミットはせずにコンフリクトが起きるかどうかだけみます。
コンフリクトを起こした場合`git pull`が正常終了せずにworkflowがそこで終了するためそれを回避するために`|| true`と書いています。

```yml
- name: merge base branch
  run: |
      git config user.name 'GitHub Actions'
      git config user.email 'actions@github.com'
      git pull origin ${{ env.BASE_REF_NAME }} --no-commit --no-ff --allow-unrelated-histories || true

  shell: bash

```

## ステップ3 コンフリクトチェック
次にコンフリクトのチェックを行います
`git diff`を使って差分を検知し`--name-only`オプションでファイル名のみを出力
それを`grep`に渡します。
`package.json`にコンフリクトが発生した場合そもそも`bun i`が実行できないためその場合は異常終了しいます。
`bun.lockb`が見つかった場合は環境変数に`boolean`を保持します。
(今回ほぼ検証なため書き方が汚いのはご愛嬌 本当は変更差分ファイル名を変数に入れるべき)

```yml
- name: Check bun lock conflict
  run: |
      if git diff --name-only --diff-filter=U | grep 'package.json'; then
        echo "package.json conflict found. please resolve package.json conflict"
        exit 1
      fi
      if git diff --name-only --diff-filter=U | grep 'bun.lockb'; then
        echo "IS_CONFLICT=true" >> $GITHUB_ENV
      else
        echo "IS_CONFLICT=false" >> $GITHUB_ENV
      fi
```

## ステップ4 コンフリクト解消
最後に`bun.lockb`のコンフリクトを解消するために`oven-sh`の`setup-bun`を使って`bun install`を実行(`bun.lockb`をあらかじめ削除する必要は多分ないけどなんとなく)
でcommitしてpushして終了

```yml
- name: setup bun
  if: env.IS_CONFLICT == 'true'
  uses: oven-sh/setup-bun@v1

- name: resolve conflict
  if: env.IS_CONFLICT == 'true'
  run: |
      rm bun.lockb
      bun install
      git add bun.lockb
      git commit -m "resolve conflict"
      git push
  shell: bash
```

## 結果

`bun.lockb`のコンフリクトをローカルでいじらずにgithub actionsでどうにかすること**は**できた

## 課題
**bun.lockb「のみ」コンフリクト起きてる場合にしか使えない**

`bun.lockb`以外にコンフリクトを起こしていた場合(よくあるのは`package.json`)
別のファイルだけブラウザエディタ上でコンフリクト解消！みたいなことはできない(以下のようになる)
![スクリーンショット 2024-01-01 22.01.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230849/cc664eb0-fa87-7afe-0c41-041dfff2cfd8.png)


そのため結局ローカルで解決しなきゃいけない

`github actions`で`bun.lockb`のコンフリクトだけ先に解決すればいんじゃん？？
って思いました。

できませんでした...
![スクリーンショット 2024-01-01 22.04.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230849/d74cf688-a843-5774-aa4e-e36a658bf0ce.png)
コンフリクトを起こしたままコミットはできず(もしかしたら他にやり方はあるのかも)

最終的な結論としては先に提示した通り`bun.lockb「のみ」コンフリクト起きてる場合にしか使えない`ということになります。

一応他に考えた解決策としては
1. 複数ファイルにコンフリクトが起きていた場合は`bun.lockb`を消すコミットを作成
2. webエディター上で開発者がコンフリクト解消
3. それを検知して`bun.lockb`を更新してコミット

とするのも思いつきましたが、そこまで`bun.lockb`のコンフリクト解消に時間かけるか...？となったため没(時間があればやるかも)になりました。

## 最後に
今回は時間をかけてそこまで機能の高くない`github actions`を作りました。
そもそもあまりgithub actionsを作った経験が多くないため割と楽しかったは楽しかったです(出来上がったものはアレですけど)

なんかこういうちょっとしたことを解消するのは割と好きで色々やってます。

同じ問題抱えて他に解決策見出した方はご教授いただけると幸いです！！！！