Technote

by sizuhiko

DependabotをGHEのActionsとPackagesで利用する

以前に DependabotをGHEのプロジェクトに適用する という記事を書きましたが それから状況は変わり CI は drone.io から GHE の Actions を使うように、プロジェクト内のプライベートパッケージは Packages に入れるようになりました。

すべて GHE のプラットフォームに寄せられたのは良かったのですが、現時点まだ Dependabot はβ版のようなので、ひとまずセルフホストランナーを使って実行できるようにしてみました。

name: dependabot
on:
  workflow_dispatch:
  schedule:
    - cron: 'お好みのスケジュールで'
jobs:
  dependabot:
    runs-on: self-hosted
    env:
      PROJECT_PATH: ${{ github.repository }}
      BRANCH: develop
      PACKAGE_MANAGER: npm_and_yarn
      GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_ACCESS_TOKEN }}
      GITHUB_ENTERPRISE_ACCESS_TOKEN: ${{ secrets.GITHUB_ENTERPRISE_ACCESS_TOKEN }}
      GITHUB_ENTERPRISE_HOSTNAME: ${{ secrets.GITHUB_ENTERPRISE_HOSTNAME }}
      NPM_REGISTRY_URL: npm.github.hoge.com
      NPM_TOKEN: ${{ secrets.PACKAGES_DOWNLOAD_TOKEN }}
    steps:
      - run: docker pull dependabot/dependabot-core
      - name: run dependabot
        run: |
          rm -rf dependabot-script
          git clone https://foo:${GITHUB_ACCESS_TOKEN}@github.com/sizuhiko/dependabot-script.git
          cd dependabot-script
          docker run -v "$(pwd):/home/dependabot/dependabot-script" \
          -w /home/dependabot/dependabot-script dependabot/dependabot-core bundle install -j 3 --path vendor
          docker run --rm -v "$(pwd):/home/dependabot/dependabot-script" \
          -w /home/dependabot/dependabot-script \
          -e PROJECT_PATH=${PROJECT_PATH} \
          -e BRANCH=${BRANCH} \
          -e PACKAGE_MANAGER=${PACKAGE_MANAGER} \
          -e GITHUB_ACCESS_TOKEN=${GITHUB_ACCESS_TOKEN} \
          -e GITHUB_ENTERPRISE_ACCESS_TOKEN=${GITHUB_ENTERPRISE_ACCESS_TOKEN} \
          -e GITHUB_ENTERPRISE_HOSTNAME=${GITHUB_ENTERPRISE_HOSTNAME} \
          -e NPM_REGISTRY_URL=${NPM_REGISTRY_URL} \
          -e NPM_TOKEN=${NPM_TOKEN} \
          dependabot/dependabot-core bundle exec ruby ./generic-update-script.rb

GHE では self-hosted ランナーを使うのが一般的なのですが、そこに dependabot を入れるのではなく、 dependabot-core の Docker イメージを使って実行できるようにします。 これは以前の記事と同じ実行方法ですね。

で、drone.io の場合と異なり Actions で該当のリポジトリで cron ビルドするようにしています。 cron のスケジュールは日次なり、週次なりで良いでしょう。

設定する環境変数

以下の環境変数でコントロールしています。

  • BRANCH PRの向き先のブランチ名。git flow の場合は develop
  • PACKAGEMANAGER パッケージマネージャ名。npmやyarnの場合は npmand_yarn
  • GITHUBACCESSTOKEN GitHubのアクセストークン。GHEのシークレットに入れておくと良いです
  • GITHUBENTERPRISEACCESS_TOKEN GHEのアクセストークン。GHEのシークレットに入れておくと良いです
  • GITHUBENTERPRISEHOSTNAME GHEのホスト名。GHEのシークレットに入れておくと良いです
  • NPMREGISTRYURL プライベートレジストリのURL
  • NPM_TOKEN パッケージダウンロード権限のあるPAT(GHEのPersonal Access Token)。GHEのシークレットに入れておくと良いです

dependabot-script を fork してみた

さて、あとは dependabot-core のイメージ内で dependabot-script を動かせば良いのですが、 dependabot-script が Github Pakages への参照ができないため、 fork して少し修正をしています。

dependabot-core はプライベートレジストリの認証に対応しているので、 scriptを少し修正して対応しています。

なお、 dependabot-script にも同様の対応のPR Read private repository credentials from environment が出ているので、いずれ公式に対応されるかもしれないです。

とくに GitHub Packages みたいなプライベートレジストリを使っていないのであれば、公式の dependabot-script を使ってもらえば良いと思います。

@swc-node/jest を使ってテストを高速化する

TypeScriptを使ってサーバーサイドのAPIサーバーなどを作っていて、テスティングフレームワークとして Jest を使っているとき まずは ts-jest を使いはじめると思います。

ts-jestはTypeScriptのコードをJestでテストするのに大変便利で、とても使いやすいのですが、コード量が多くなってきたときCI/CDにおける テスト時間が問題になってきます。

Jest + TypeScript のテストを高速化するノウハウ

このあたりはすでに多くのブログ記事が出ているように、ググるとたくさんの情報が出てきます。

などなど…

これらで書かれているもので、共通してくるワードが

です。 どちらも esbuild(Goで書かれている) や swc(Rustで書かれている) といった高速のトランスパイラを使って実行するので、 Jestのテストが速くなります。

TypeScript も様々

では実際に esbuild や swc を簡単に導入できるかということです。 TypeScript で、特にサーバーサイドの実装の場合、いろいろな機能を使っている場合があります。 たとえば DI であったり、 ORM であったり。 私が関わっているプロジェクトでも DI フレームワークとして tsyringe を、 ORM で typeorm を使っています。 これらのライブラリは TypeScript の DI や ORM としては一番に思いつく有名どことで特にマニアックなライブラリではないと思います。

で、これらのライブラリを使う上では、 tsconfig に以下の設定を入れる必要があります。

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

さて、そこで問題になるのが esbuild です。 esbuild ではデコレータのサポートがないので、まず候補から外しました (もちろん esbuild-decorators という拡張があるのも知ってはいますが、公式ではないうえ、これ自体がTypeScriptで書かれているので実行速度的に結局美味しくないというのがあります)。

そうすると、 swc を使うことになるのです。 swc はデコレータにも対応しており、理想的です。

@swc/jest の使い勝手

@swc/jest を使って速くなったという記事のソースコードは単純なサンプルであることが多く、実際に単純に導入するだけではうまくいきません。 もちろんうまく動作するプロジェクトもそれなりにはあるでしょうが。

swc では tsconfig を解釈してくれるわけではないので、 .swcrc でコンフィグを書く必要があります。 これが微妙に tsconfig と違うので、ビルドでは swc を使わず webback と serverless framework で AWS Lambda にデプロイするような APIサーバーでは設定を合わせるのが面倒です。

@swc-node/jest という解決策

そこで調べていくと、 @swc-node という swc をより node.js 環境に特化したラッパーがあることを知りましt。

で、 @swc-node には @swc-node/jest というパッケージがあり、 これは @swc/jest と対になっている関係ですね。

@swc-node も tsconfig を解釈してくれるわけではないのですが、オプションの項目は tsconfig を一致しているので特に迷いなく設定できます。

ちなみに 1.5系からは tsconfig を読み込むように変更されているのですが、現時点私たちのプロジェクトではビルドが失敗するので、まだ 1.4 系を利用しています。 問題はすでに issue TypeScript path mapping is not working. になっており、 パスエイリアスを使っているときに、うまくファイルが import できないところなのですが、これが解決されれば transformer の設定も不要になるので、 とても便利になるはずです。

ところで、この @swc-node ですが、当初(私たちが採用を決めたとき)は @Brooooooklyn さんの個人リポジトリにあったと思うのですが、現在は @swc-project 配下に移動しています。 プロジェクトの一部になったというのは、一つ安心材料ですね。

@swc-node も TypeScript で書かれていて、 esbuild-decorators と同じじゃないのか?という話はあるかもしれませんが、 @swc-node に関していうと、これは tsconfig の設定値を swcrc にマッピングするラッパーという感じなので、動作時は swc 相当となります(実際に測定値もGitHubに出ている)。

もし、サーバーサイドのTypeScriptプロジェクトで同様の課題を持っている人がいたら、 @swc-node の利用を試してもらえると良いかなと思っています。 私たちはCIの時間を劇的に改善することができました。

pong-swoosh のアップデートまとめ

昨年リリースした pong-swoosh ですが、いつくかのアップデートを重ねてより使いやすくなっている、と感想もいただいております。 そこで、これまでのアップデートをまとめて紹介します。

βバージョン

実はブログで公表する以前に、身内で試していたβバージョンがあり、そのときはTOPページでチャンネルを開設すると、

  • コントローラページ
  • スピーカーページ

の2つのURLを共有してもらうように、表示されていました。

すると、2つ共有するのが面倒であるといった意見があり、エントランスページというのを作り、そこに2つのURLとQRコードを載せることにしました。 これが処理リリースバージョン(以前のブログ オンラインイベントの盛り上がりを効果音で共有するサービス pong-swoosh を作成した で紹介したものです。

初期バージョン

しばらくはデザインの変更はなく、Socket.io 周辺で接続が切れたり、Herokuのインスタンスが再起動したときの再接続などを解消するのがメインでした。

これらの対処で基本的な安定接続が保たれ、ユーザー体験を改善することにフォーカスしていきました。

UIの改善

ここで、いくつかの改善が実施されました。

音量がバラバラな感じだったので、調整しました。 参加人数に関しては、表示して欲しいという要望があったので、スピーカー画面に表示するよう追加されました。

Herokuのインスタンスがしばらくアクセスされていない、初期起動の状態だとチャンネル作成に時間がかかり 何度も作成ボタンを押してしまうトラブルがあったので、すぐにローディング画面へ切り替えるように。

初期のコンセプトでもあった

オンラインでイベントに参加すると、参加者一覧の画面と、スライドなど画面共有された画面の2つを常に表示していると思います。 かなり大きなディスプレイを使っていれば、余裕があるかもしれないのですが、ノートPCとそれほど大きくない外部モニターだと、それぞれが最大表示されていて、画面には余白がないのでは?と思います(私もそうです)。 そこで、コントローラー画面はスマホでアクセスして利用しやすいように設計されています。 スピーカー画面は、最初に音量調整すれば特に前面に表示している必要がないので、Web会議システムと同じPCで開くことが想定されています。 もちろんWeb会議の音と混じるのが嫌な人もいると思うので、どちらもスマホからアクセスしやすいようにQRコードを表示するようにしています。

この考え方、エントランスページからスピーカーはPC、コントローラはスマホ、というのが思いの外PCのみでも操作で良い人が多いということがわかりました。 なので、エントランスページはなくして、共有されたURLがいきなり参加者側のアプリケーション画面という流れにしました。 なので、共有したURLから画面遷移する必要がありません。 参加者画面にはスマホでコントローラを表示できるQRコードを表示するようにしたので、もしスマホから操作という場合も従来のステップ数からは 変更なく利用できるようになっています。

速度の改善

これまではSocket.ioのメッセージの中にバイナリで効果音を送信するようにしていたのですが、同じオリジンに効果音を設置するようにし、 ブラウザから効果音をロードする変更を実施しました。 これによって、効果音ボタンを押したときにブロードキャストされるメッセージは効果音IDぐらいになってので、送信コストが下がりより大人数でも時差なく 効果音が鳴るようになりました(これまでは30人ぐらいのイベントだと少しタイムラグがあった)。

テストコードの追加

OSSでの活動でもあるので、多くの人から改善リクエストを受け付けられるように、サーバーサイドからテストコードを追加しています。 まだ途中ですが、フロントエンドがSveltteということもあり、そのテストツールでもある uvu を利用しています。

実は pong-swoosh はプライベートβから1周年

pong-swoosh の初期実装をプライベートβで利用し始めたのは、ちょうど1年前のGW明けでした。 そのときに、まだオンラインカンファレンスやミーティングがどのぐらい続くのかわからない中、まだ必要としてくれる人がいれば、という思いではじめてきて 1年が経過しようとしています。

まだオンラインの需要はあるようですので、引き続き pong-swoosh の改善をしていきたいと思います。

オンラインイベントの盛り上がりを効果音で共有するサービス pong-swoosh を作成した

前回のBlog更新が1年半近く前の、最後のオフラインイベントだったでしょうか…. それから、書くまでもありませんが、イベントや仕事がすべてオンラインで行われるようになりました。

私たちインターネットに関連する仕事をしているものは、特に在宅でも同じように仕事を進めています(僕の場合は家の環境が劣悪というのはありますが)。

変わったのは勉強会やカンファレンス、コミュニティ活動がオンラインになったり、そもそも開催されなくなったりといったことがあります。

僕も昨年中はずっとモチベーションもダダ下がりで、ただ仕事をして何となくYoutubeで動画見るみたいな繰り返しを送っていました。 オンラインの勉強会やカンファレンスにも参加する気になれなかった、というのが本当のところです。

お前は懇親会とか飲み会メインだろ?とか言われると、まぁ否定もできないのですが、リアルな共感が得られない(廊下カンファレンスができない)とか、ちゃんとした理由もあったりします。 僕は必ず前方の席で参加するし、リアクションも他の人と比べるとある方かなーと思っています。 オンラインは、どうしても講義形式になりがちだし、参加している人同士がこういうことに関心があるんだとか、面白いと思ったり感動したりするんだな、ということは得られないな、と思っています。 もちろんチャットやTwitterなど、文字と盛り上がりが共有できたり、ログとして残ったりするんですが、どうしてもWeb会議システムで登壇者の顔、スライドを観ながらチャットも、となると注意力が分散したり、スクリーン数の限界とかにも達するなーと思っています。

目は2つしかない。

社内勉強会きっかけ

さて少し話題は変わりますが、僕は所属している会社でIoT勉強会というのを主催していて、これまでトイレ利用状況可視化サービスToilet Evolution、常駐先などから社員証で出退勤できるデバイスとサービスdakokuといったものを開発してきました。 IoT勉強会はデバイスなんかを作ることもあったので、会社で購入した工具なんかを共有で使ったりしていたわけですが、同様にオンラインとなると難しくなります。 そこで、何とかオンライン時代のサービスをIoTという文脈で作り出せないかな、と思い続けてきて今回の効果音共有サービスを開発するに至りました。 IoTはモノのインターネットですが、オンラインイベントに参加する盛り上がりや人の感情をモノと見立てて、インターネットで共有するのがオンラインイベントでは有益なのでは?と思っています。

pong-swoosh

在宅になって、ずっとFMラジオを聴きながら仕事をしていたりするのですが、DJの人が拍手なんかをサウンドマシーンで出すシーンがありますよね。 あれを ポン出し なんて言ったりします。 今回作ったサービスは、ポン(効果音)を投げる(チャットの文字送信みたいなイメージ)というところから、pong swoosh という名前にしました。 (日本酒が好きだからポンシュ、なんてことじゃないです。)

どんなサービスか

pong-swooshは、Web会議システムを利用しながら効果音を送受信して、盛り上がりを共有するシステムです。 使い方は簡単なので、まずは使ってみましょう。

まずはチャンネルを作成する

チャンネルとは効果音を共有する部屋の単位です。pong-swooshは効果音チャットシステムのようなものなので、チャットでよく使うチャンネルという単語を利用しています。

トップページにアクセスして、チャンネル名を入力して作成します。

そうすると、チャンネルのURLが表示されるので、これを参加者に共有します。 1URLだけなので、イベントサイトだったり、Web会議のチャットだったりで共有できますね。

コピーアイコンで簡単にクリップボードにもコピーできます。

参加者がアクセスする

共有されたURLにアクセスすると、エントランスページが表示されます。

pong-swooshには

  • コントローラー画面(効果音を送信する画面
  • スピーカー画面(効果音を再生する画面

というものがあります。 なぜ画面を分けたか?というのには理由があります。

オンラインでイベントに参加すると、参加者一覧の画面と、スライドなど画面共有された画面の2つを常に表示していると思います。 かなり大きなディスプレイを使っていれば、余裕があるかもしれないのですが、ノートPCとそれほど大きくない外部モニターだと、それぞれが最大表示されていて、画面には余白がないのでは?と思います(私もそうです)。

そこで、コントローラー画面はスマホでアクセスして利用しやすいように設計されています。 スピーカー画面は、最初に音量調整すれば特に前面に表示している必要がないので、Web会議システムと同じPCで開くことが想定されています。 もちろんWeb会議の音と混じるのが嫌な人もいると思うので、どちらもスマホからアクセスしやすいようにQRコードを表示するようにしています。

コントローラー画面

このスクショは、PullRequest中のものなので、この記事を読んですぐ試した方は違う画面になります(近いうちに変わります)。

コントローラー画面には効果音を参加者に共有(送信)するボタンと、実際にどんな音が鳴るのか送信せずに確認する 視聴 リンクがあります。

スピーカー画面

このスクショも、PullRequest中のものなので、この記事を読んですぐ試した方は違う画面になります(近いうちに変わります)。

ボリュームのスライダーがあるので、各自の環境に応じて音量を調整できます。 音量は参加者の人数と同じ効果音を同時(1秒以内)にリアクションした人の数で変化します。 計算式は以下のとおりです。

Math.sin(Math.PI * 90 * (同時にリアクションした人の数 / チャンネル参加者数) /180) * 2;

最初は直線的に音量が上がるようになっていたのですが、途中から円弧に沿って上がるように変更しています。 同時にリアクションした人の数を集計するのに、RedisのINCR/DECRコマンドを使っています。 チャンネル名と効果音IDをキーにINCRで人数を加算して、1秒後にDECRするといったことで音量が変化します。

技術的な話

前にも書きましたが、pong-swooshは効果音チャットシステムのようなものです。 サーバーとの送受信にはsocket.ioが使われていて、効果音が送信されてくるとチャンネル参加者にブロードキャストされます。 簡単なチャットプログラムを作ったことがあれば容易に想像できるシステムです。 バックエンドはNode.jsで書かれていて、現在はHeroku(無料プラン)にデプロイされています。 フロントエンドはSvelteを使っていて、GitHub Pagesにデプロイされています。 バックエンドは手動デプロイですが、フロントエンドはGitHub Actionsでmainにマージされると自動的にデプロイされるようになっています。

勉強会メンバーで開発していますが、ソースコードは公開されています。 https://github.com/its-succ/pong-swoosh

さいごに

pong-swooshは、現在自分が担当しているプロジェクトのスクラムイベントと、会社の部門メンバーが月一で集まるミーティングで利用して改善を重ねてきました。 スプリントレビューのデモや、ふりかえり、プレゼンテーションなどの場で効果音を使ってリアクションを共有しています。

それまでは画面越しに拍手をしてみたり(音は出さず映像で)だったのですが、pong-swooshを使うことで賑やかになったといったフィードバックをもらったりしています。

もちろんこういった共有の方法が合う場面、合わない場面などあるかもしれないのですが、もし興味があれば使ってみてください。 そんなに重い処理もないので、Herokuの無料枠で使ってもらっていても問題ないかな?と思っています。

もし使ってみてフィードバックがあれば、GitHubのissueなどに報告してもらえると嬉しいです。 もちろんPRという形で参加いただくのもWelcomeです。

いつかオフラインで昔のように勉強会やカンファレンスができるときが来ると良いのですが、 もうしばらくオンラインが続きそうな感じでもあります。 そんなとき pong-swoosh が少しでもお役に立てれば幸いです。

PHPerKaigi 2020で「E2Eテストに向き合う」ついて発表してきました

昨年に続いてPHPerKaigiに参加できました。 今年は 2/9(日), 2/10((月), 2/11(祝) の3日間の開催で、私はメインセッションが行われる10,11の2日間参加しました。

2日間の過ごし方は、概ね以下のような感じでした。

  • 2/10
    • 午前中は登壇とAsk The Speaker
    • 午後一はPHPの現場公開収録に参加
    • CI/CDのIRTに参加
    • ルームCで歓談
    • PHPer茶会に参加
  • 2/11
    • ルームCで歓談
    • ランチセッションに参加
    • @hnwさんのZend VMにおける例外の実装に参加
    • コードゴルフやったりアジャイルIRTやったりルームCで歓談
    • 懇親会に参加

ほとんどルームCで誰かと話していた感じですね。 でもPHPerKaigiのコンセプトには合っているはず。

「E2Eテストに向き合う」

E2Eテストに向き合うというタイトルで登壇しました。

Puppeteerについて、昨年も何回か登壇する機会があったのですが、 視点を変えてE2Eテストから見たときの考え方/ツールとしての可能性/有用性を話したかったのと、 テスティングピラミッドの背景みたいなところから自動テストについて理解が深まると良いなという思いでした。

最後のスライドでも紹介したPlaywrightのREADMEに書かれている Q: What about the WebDriver?の 下りは、私が特に感銘を受けているところです。

Webブラウザを使ったE2EテストやUIテストの自動化はWebDriverなしには、 ここまでにはなっていなかっただろうし、そういう意味で「普遍的な標準」であると私も思います。

一方でPWAなど新しい技術、新しいWebの登場により、自動テストが困難になっていることも事実です。

私たちWebに関わるプログラマは、こういった局面においてより多くの事実と事例を積み上げて標準にフィードバックするという姿勢が必要だと思っています。 なぜなら「みんなのインターネット」だから。

これはテスト自動化に関わらず、Webの標準についても同じだと思っています。 HTMLやCSS、はたまたブラウザに新しく追加される機能、どれも最初は少しユースケースが見えないものだったり、 遅くて使い物にならないものかもしれません。 でもその有用性や可能性、必要性がある人が結果を積み重ねることで、少しずつデファクトスタンダートに 近づいていく、これが現在のWebに関する標準の進み方だと思っています。

The Extensible Web Manifestoの宣言から7年。 フィードバックループにおける標準化の流れは現実になってきていると思っています。 いつかWebDriverにも同様のユースケースが取り入れられることを願って、今はそれぞれのWebアプリケーションに適したツールや環境を使い、アプリケーションの品質や、リリースサイクルの効率化ができると良いなと思います。

さいごに

PHPerKaigiは今年も楽しめました。 交流スペースで多くの人と、様々な話題について議論できました。

今年たくさんのノベルティがあって、その中にトレーディングカードがありました。

名札の右に立てて置いているものです。

私はTwitterもアカウント名だし、Publicにいろいろなことやっているからあまり気にならなかったのですが、 Twitterアカウントが実名だったり、写真も実写だったりする人もいますよね。

で、実際イベント期間中に PHPerKaigi の残念なところ(どういう風に利用されてしまうかわからず怖い)として Twitter に書き込みをされている方がいました (私はたまたまイベントのハッシュタグ付きで呟かれてたのをTL上で見たのですが)。

個人的にはトレーディングカード確かに面白いし、名刺代わり?になって便利だなーと思ったけど、 事前にあまり告知されていなかったこともあり、個人情報の利用という観点からはちょっと微妙かもなーと思いました。 申し込み時に拒否できたり、個人情報(写真や名前)が含まれないデフォルトカード?てきなものが選択できても良かったのかも。(とにかくみんな持っている/交換するみたいな雰囲気だったので、持ってないよりは良さそう、カード作成後に申し込みした人はそれに近い扱いだった模様)。

あと、トレカたくさん余っているので、これの使い道もどうしたら良いか考えたいw