• トップ
  • ブログ一覧
  • 自作のChrome拡張を使って業務効率化をしてみる
  • 自作のChrome拡張を使って業務効率化をしてみる

    ちょっとした作業を効率化するためにシェルスクリプトや簡単なコードを作って楽をすることはエンジニアではよくあることかと思います。
    その一環としてChromeの拡張機能を作るのも意外と便利だよ、というお話です。

    作りたいもの

    今回作るのはGitHubのプルリクエストに対する拡張です。プルリクエストが大きくなると、全てのコメントに対応したかどうか分かり辛くなることがあるので指摘数を一目でわかるようなブラウザ拡張を作ってみようと思います。
    具体的にはFiles changedタブを開いた際に画面の適当な部分にコメント数や解決数を表示してくれる、といったものを目指します。

    必要な手順

    manifest.jsonの作成

    まずはChrome拡張として認識されるためのmanifest.jsonファイルを作成します。

    1{
    2    "manifest_version": 3,
    3    "name": "GitHubのコメント数を表示",
    4    "version": "1.0",
    5    "permissions": [],
    6    "content_scripts": [
    7      {
    8        "matches": ["https://github.com/*/pull/*"],
    9        "js": ["content.js"],
    10        "css": ["styles.css"]
    11      }
    12    ]
    13}

    manifestを作るにあたって必須のキーはmanifest_version,name,versionの三種です。manifest_versionは現在3のみサポートされているので固定値として3、名前とバージョン情報は好きな値を設定します。ストアに公開する場合は説明文(description)やアイコン(icon)も必須ですが今回のような自分用であれば不要です。

    content_scriptsはざっくり説明すると「特定のページを開いた時に特定のファイルを読み込む」キーです。今回の場合はmatchesに書かれたURLを開いた際指定したJavaScript(とCSS)を読み込む、といった動作をさせます。ワイルドカードを組み合わせてGitHubのプルリクエスト(/pull)をmatchesを設定しています。今回のはプルリクエストのFiles changedタブのみ用があるので/filesまで指定したいところですが、何かと不便だったのでURLの判定はJavaScriptで行うようにしています。

    permissionは外部の通信やデータ参照を行う際に適宜必要なものを記述します。今回は不要です。

    JavaScriptの作成

    manifest.jsonと同じディレクトリにcontent.jsを作成します。読み込むJavaScriptはこんな感じです。

    1// コメント数をカウントし画面に表示/更新
    2function updateCommentCountOverlay() {
    3    const commentElements = document.querySelectorAll('.js-comment-container');
    4    const totalComments = commentElements.length;
    5    let resolvedComments = 0;
    6
    7    commentElements.forEach(commentElement => {
    8        let hasResolvedText = false;
    9        const resolvedTextContainer = commentElement.querySelector('.d-lg-inline.d-block.px-md-0.px-3.pb-md-0.pb-3');
    10        if (resolvedTextContainer && resolvedTextContainer.textContent.includes('marked this conversation as resolved.')) {
    11            hasResolvedText = true;
    12        }
    13        const hasThumbsUpReaction = !!commentElement.querySelector('[id^="reactions--reaction_button_component-"][value="THUMBS_UP unreact"]');
    14        
    15        const isResolved = hasResolvedText || hasThumbsUpReaction;
    16        if (isResolved) {
    17            resolvedComments++;
    18        }
    19    });
    20
    21    let overlay = document.getElementById('github-comment-counter-overlay');
    22    if (!overlay) {
    23        overlay = document.createElement('div');
    24        overlay.id = 'github-comment-counter-overlay';
    25        document.body.appendChild(overlay);
    26    }
    27
    28    overlay.textContent = `指摘: ${totalComments}, 解決済: ${resolvedComments}`;
    29    if (totalComments !== resolvedComments) {
    30        overlay.style.backgroundColor = 'red';
    31    } else {
    32        overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
    33    }
    34}
    35
    36// File changedタブかどうかを判定しオブサーバをセット
    37function checkAndUpdateOnFilesTab() {
    38    if (window.location.href.includes('/pull/') && window.location.href.endsWith('/files')) {
    39        updateCommentCountOverlay();
    40
    41        const observeTarget = document.querySelector('#files_bucket');
    42
    43        if (observeTarget) {
    44            const observer = new MutationObserver(updateCommentCountOverlay);
    45            observer.observe(observeTarget, { subtree: true, childList: true, attributes: false, characterData: false });
    46        }
    47    } else {
    48        const overlay = document.getElementById('github-comment-counter-overlay');
    49        if (overlay) {
    50            overlay.remove();
    51        }
    52    }
    53}
    54
    55window.addEventListener('turbo:load', checkAndUpdateOnFilesTab);

    現在のGitHubはTurboを使用して画面描画を行なっているようなので、window.addEventListener('turbo:load', hoge)で画面遷移のロードを検知し処理を実行できます。あとはquerySelectorやgetElementByIdで指摘コメントや解決済みコメントの要素をいい感じに検索し数をカウントするだけです。現在のGitHubではコメントは'.js-comment-container'、解決済み(marked this conversation as resolved.テキストが表示されている状態)は'.d-lg-inline.d-block.px-md-0.px-3.pb-md-0.pb-3'ので探索するとうまく取得できました。また個人的な運用としてサムズアップ👍アイコンも解決済みとしてカウントするようにしています。このような自分用カスタムができるのが自作プラグインのいい所ですね。
    最終的にCSVで定義したelementを作成しappendChildでUIに貼り付けています。また、ページ内で解決済に変更した場合に更新されるようObserverも設定しました。

    CSSの作成

    最後にelementのデザインを決めるCSSを作成します。今回はjsファイルと分けましたが、自分用と割り切ってしまうならJavaScript内に入れてしまっても良いと思います。

    1#github-comment-counter-overlay {
    2    position: fixed;
    3    top: 10px;
    4    right: 10px;
    5    background-color: rgba(0, 0, 0, 0.7);
    6    color: white;
    7    padding: 8px 12px;
    8    border-radius: 5px;
    9    font-size: 14px;
    10    z-index: 9999;
    11  }

    プラグインを適用する

    最後に作成したプラグインの適用です。まずはchrome://extensions/にアクセスし。右上のデベロッパーモードをONにします。

    「パッケージ化されていない拡張機能を読み込む」が表示されるので作成したmanifest,JavaScript,CSSの入ったディレクトリを指定します。

    これで追加が完了します。コードに手を加えた際はプラグインの再読み込みボタンを押すことですぐに反映されます。

    動作確認

    ここまでで完成した動作を見てみます。

    適当なプルリクエストを開き、Files changedタブを開くと、


    画面遷移されたこととURL、画面の要素をそれぞれ検知し、画面右上に指摘数カウントのUIが表示されました。


    コメントをしたりResolvedを押すとこのように指摘数や解決数が更新されます。また、指摘数と解決数が一致しない場合は背景を赤色で表示するようにしました。
    これで確認漏れを防ぐことができ、レビューのやり取りで事故が起こりにくくなりました。

    まとめ

    一見専門的なChrome拡張ですが、自分用ならSDKもIDEも鍵や署名も不要とかなりお手軽に作ることができます。
    ハードルはかなり低いのでぜひ試してみてください。

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    すどたく(エンジニア)
    すどたく(エンジニア)
    Show more...

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background