LoginSignup
3
1

はじめに

bunのバージョンが1.0.0になりましたね!!🎉(3ヶ月前)

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

目的

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

現状の課題

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

しかしブラウザ上のエディタではバイナリデータのコンフリクトは解消できません(以下のような表示が出る。)
スクリーンショット 2024-01-01 21.37.26.png

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

アプローチ

github actionsを使って色々コネコネします。
自動でコンフリクト解消してもいいのですが気づかない間に変な変更されるのも嫌なのでworkflowのトリガーは手動にします。
先に作成した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のマージ先のブランチを保持しておきます

- 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と書いています。

- 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を保持します。
(今回ほぼ検証なため書き方が汚いのはご愛嬌 本当は変更差分ファイル名を変数に入れるべき)

- 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-shsetup-bunを使ってbun installを実行(bun.lockbをあらかじめ削除する必要は多分ないけどなんとなく)
でcommitしてpushして終了

- 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

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

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

できませんでした...
スクリーンショット 2024-01-01 22.04.22.png
コンフリクトを起こしたままコミットはできず(もしかしたら他にやり方はあるのかも)

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

一応他に考えた解決策としては

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

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

最後に

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

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

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

3
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
3
1