はじめに
bun
のバージョンが1.0.0
になりましたね!!🎉(3ヶ月前)
最近よくbunをpackage managerとして使ってるのですがいかんせんコンフリクトがめんどくさすぎてどうにかならないかなぁと思って今回どうにかしたかった話をします。
目的
最終的な目標はbun.lockb
のコンフリクトをローカルでいじらずにgithub actionsでどうにかすること。
現状の課題
githubのプルリクエストにてコンフリクトが起きます
その場合ローカルでマージしてpush
またはブラウザ上のエディタでコンフリクトを解消する必要があります。
いかんせん前者は必要な工程がチョット多くてめんどくさい(そこまででもない)のでどうにかブラウザ上のエディタでどうにかしたいです。
しかしブラウザ上のエディタではバイナリデータのコンフリクトは解消できません(以下のような表示が出る。)
こうなるともうブラウザエディタ上ではコンフリクトは解消できません
ローカルでマージ元とマージ先を更新してマージ元にマージ先をマージして起きたコンフリクトをローカルで解消するしかありません。
正直lockファイルのためにこれをやるのはめんどくさいです
というのもbun.lockb
のコンフリクトはbun i
を再実行すればpackage.json
を元に再生成されるのでそこまで必要な操作もないんです
てことでこれをいい感じにしていきます。
アプローチ
github actionsを使って色々コネコネします。
自動でコンフリクト解消してもいいのですが気づかない間に変な変更されるのも嫌なのでworkflowのトリガーは手動にします。
先に作成した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-sh
のsetup-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
)
別のファイルだけブラウザエディタ上でコンフリクト解消!みたいなことはできない(以下のようになる)
そのため結局ローカルで解決しなきゃいけない
github actions
でbun.lockb
のコンフリクトだけ先に解決すればいんじゃん??
って思いました。
できませんでした...
コンフリクトを起こしたままコミットはできず(もしかしたら他にやり方はあるのかも)
最終的な結論としては先に提示した通りbun.lockb「のみ」コンフリクト起きてる場合にしか使えない
ということになります。
一応他に考えた解決策としては
- 複数ファイルにコンフリクトが起きていた場合は
bun.lockb
を消すコミットを作成 - webエディター上で開発者がコンフリクト解消
- それを検知して
bun.lockb
を更新してコミット
とするのも思いつきましたが、そこまでbun.lockb
のコンフリクト解消に時間かけるか...?となったため没(時間があればやるかも)になりました。
最後に
今回は時間をかけてそこまで機能の高くないgithub actions
を作りました。
そもそもあまりgithub actionsを作った経験が多くないため割と楽しかったは楽しかったです(出来上がったものはアレですけど)
なんかこういうちょっとしたことを解消するのは割と好きで色々やってます。
同じ問題抱えて他に解決策見出した方はご教授いただけると幸いです!!!!