くりにっき

フルスタックキュアエンジニアです

GitLab client-goにパッチが取り込まれた

GitLab client-go(GitLab APIのGoクライアント)に僕が投げたパッチがいくつかとりこまれたので紹介

gitlab.com

1つ目のパッチ:Add gitlab.WithRequestRetry to retry with any status code

gitlab.com

client-goには https://github.com/hashicorp/go-retryablehttp が組み込まれていて、特定のステータス(429エラー、500系エラー)の時には自動リトライする機能があります。

多くの場合はこれで問題ありません。

しかし、MergeRequest(GitHubでいうところのPullRequest)作成直後にAuto mergeを設定しようとすると402エラーや422エラーになることがあるためリトライが必要になります。 *1

そのため任意のAPI呼び出しで任意のステータスコードでリトライ可能にできるようにする機能を追加しました。

実はRubyKaigi前くらいにパッチを投げていたのですが、色々ディスカッションがあってなんやかんやでマージされるまで1ヶ月くらいかかりました。

余談ですが context.Context をガッツリ使ったのは今回が初めてでした。(処理を追加する場所的にcontextを使う以外に方法がなかった)

このパッチはマージされていてv0.129.0でリリースされています。

gitlab.com

2つ目のパッチ:Fixed HTTPClient in retryablehttp.Client not taking over in newRetryableHTTPClientWithRetryCheck

gitlab.com

自分のアプリのテストコードでは https://github.com/jarcoal/httpmock でGitLab APIの通信をモックしていました。

client-go v0.129.0を自分のアプリで使おうとしたところ、自分が実装した gitlab.WithRequestRetry を使った時だけhttpmockが効かないバグがあったので修正したのがこのパッチです。

自分のアプリの場合テストコードでhttpmockを使うためにHTTPClientを明示的に渡す必要があったのですが、gitlab.WithRequestRetry を使うとそれが消えてデフォルトのHTTPClientに戻るためhttpmockが効かなくなるというのが原因でした。

このパッチはマージされていてv0.130.0でリリースされています。

gitlab.com

何が嬉しいか?

冒頭に書いた、MergeRequestの作成直後にAuto mergeを設定しようとすると402エラーや422エラーになる件の対策として汚い実装を入れていたのですが、v0.130.0のおかげでその辺の実装を消してきれいにすることができました。

gitlab.com

zatsu_monitor v2.0.0, tanuki_reminder v1.0.0をリリースした

それぞれ内部で使ってるYAMLのライブラリを差し替えたことによるメジャーバージョンアップ

元々 gopkg.in/yaml を使ってたのですが今年の4月にリポジトリアーカイブされてメンテされなくなってしまいました。

最近は https://github.com/goccy/go-yaml が割と使われてるという話を聞いてこれに移行しました。

既存のテストはパスしてるのでまあ問題ないだろうなあと思いつつもエッジケースで挙動が変わってると嫌なので念の為メジャーバージョンを上げました。

https://github.com/sue445/zatsu_monitor/pull/151/fileshttps://gitlab.com/sue445/tanuki_reminder/-/merge_requests/242/diffs を見てもらえれば分かるように、コードはimportの中身くらいしか変更していないので移行はむっちゃ楽でした。

関西Ruby会議08の不採択Proposalを公開

前置き

関西Ruby会議08 のProposalが不採択だったんですがkinoppydさんに影響されて公開してみます。

Title

Rearchitecturings of regional-rb-calendar

Abstract

皆さんは地域.rbカレンダー( https://sue445.github.io/regional-rb-calendar/ )というのをご存知でしょうか?

2019年にリリースして以降、様々なRubyistの方たちに利用されてきたと思います。

この6年間見た目はさほど変わっていないのですが、実はインフラを含めた裏側のアーキテクチャは地味に変遷してきました。問題解決のために必要に応じてgemもいくつか作ってきました。

今回は地域.rbカレンダーのリアーキテクチャリングの変遷を紹介したいと思います。

Details

地域.rbカレンダーは大きく分けて下記のフェーズがあるのでそれぞれに関して話したり話さなかったりします

2019/08: なにもなかったサーバサイド

2020/02: AppEngine

2021/01: Heroku

  • 詳しい理由は覚えてないんだけどたぶん運用しやすさからHerokuに移行した気がする
  • https://github.com/sue445/regional-rb-calendar/pull/111
  • 今まで色んなIaaSやPaaSなどを使ってきましたがgit push heroku mainでデプロイできる開発体験はいまだに超えれてない

2022/09: Cloud Run Functions

2022/09: Doorkeeper APIを直接呼ぶようにした

2024/05: Connpass API v1の仕様変更

2025/04: Connpass API v2への移行

Pitch

https://sue445.github.io/my-ci-badges/ を見てもらえれば分かるように、僕は地域.rbカレンダー以外にもたくさんのOSSをメンテしてきてます。僕の代表作の https://github.com/sue445/rubicure は10年以上メンテしてますが、これだけ多くのOSSを長くメンテしてる人はあまりいないと思います。

https://github.com/gayanvoice/top-github-users/blob/main/markdown/public_contributions/japan.md によると僕は日本国内でトップ10に入ってるので(プロポーザル執筆時点)、それなりに活発にOSS開発してる方だと思います。

僕がメンテしてるOSSにしては珍しく様々な方々がパッチを送ってきてくれてます。 https://github.com/sue445/regional-rb-calendar/graphs/contributors

今回はそのようなRubyist達によって作られた地域.rbカレンダーという1つのアプリケーション(?)を通して、どのようにリアーキテクチャリングしてきたのかを話そうと思ってます。

Speaker Bio

https://github.com/sue445

x_post_sanitizerというgemを作った

x_post_sanitizerとは

github.com

Xのポストに含まれる t.co のような短縮URLを展開したりその他いい感じにするgemです。

だいぶ前に作った https://github.com/sue445/tweet_sanitizer の後継にあたります。

sue445.hatenablog.com

モチベーション

tweet_sanitizerは https://github.com/sferik/twitter-ruby に依存してたのですが、TwitterがXになった後くらいにメンテされなくなって https://github.com/sferik/x-ruby を使うのが推奨されてきました。

しかし僕は https://github.com/yhara/simple_twitter をメンテしている *1からsimple_twitterを使うことが多いです。

そのため、tweet_sanitizerを特定のgemに依存しない形で作り直したのがx_post_sanitizerになります。

tweet_sanitizerにあったテストケースは全部x_post_sanitizerにも移植してパスしてるので互換性はあると思います。

さすがに https://github.com/sferik/twitter-ruby を使ってる人はもういないだろうと思ってtweet_sanitizerの方はこの機会にアーカイブしました。

*1:メンテナになった経緯は https://sue445.hatenablog.com/entry/2023/07/17/232005 を参照

rspec-parameterized v2.0.0をリリースした

github.com

https://github.com/tomykaira/rspec-parameterized/blob/master/CHANGELOG.md#v200-2025-05-02

主な変更点

https://github.com/whitequark/parserRuby 3.4以降では積極的にサポートしないようです。 *1

そのため、Ruby 3.4以降では https://github.com/ruby/prism を使うようにしました。

prismがRuby 2.7以降しかサポートしていないため2.7未満のサポートをきっています。

parserとprismの両方をruntime dependencyにするのは賛否両論ありそうな気もしますがrubocop-astがやってる *2なら許されるかなと思って両方追加してます。

(利用者側でgemをバージョンアップする時に bundle update 以外の手作業が発生すると大変なので両方を依存に追加するのが安牌そうではある)

荷物ストラテジー

前置き

先人たちに影響されたので書きました。(RubyKaigiに限ったことじゃないのであえてタイトルにRubyKaigiはつけていないです)

d.s01.ninja

ima1zumi.hatenadiary.jp

osyoyu.com

bash0c7official.fanbox.cc

登壇報告ブログは別で出します

基本戦略

  • 泊まりはキャリーバッグ
  • 日帰りはリュック

持ち物チェックリスト

個人ドキュメントは esa にまとめています。

遠出する時の持ち物は自分の中でだいたい決まっているのでesa投稿テンプレート を使って管理しています。

公開用に若干編集してるけど実際に使ってるやつとほぼ同じです。

自分の場合は泊まり用とライブ用の持ち物チェックリストを1つのテンプレで管理してます。

# 泊まり
* [ ] 薬
    * (薬名A)x (n泊数)
    * (薬名B)x (n泊数)
* [ ] スマホ充電器
* [ ] 延長タップ
* [ ] ポケモンGo++
* [ ] Kindle
* [ ] garmin充電器
* [ ] AirTag
* [ ] 予備の腕時計
* [ ] 折り畳み傘
* [ ] ウエストポーチ


## TODO
* [ ] 目覚まし時計を全部止める

# カンファレンス
* [ ] 名刺
* [ ] マイバッグ
* [ ] 栗アイコンシール

# ライブ
* [ ] チケット
* [ ] ライト
* [ ] タオル
* [ ] 飲み物
* [ ] 痛バ
* [ ] ぬい
* [ ] Kindle
* [ ] 折りたたみマイバッグ
* [ ] 折り畳み傘
* [ ] 充電器

RubyKaigi 2025の時はこんな感じ。テンプレからページを作った後にちょいちょいカスタマイズしています。

説明

持病の毎日薬を飲む必要があるので持って行く数を泊数から出せるようにしてます。

エストポーチ

PCを入れる用のリュックは大きいので懇親会会場だと邪魔になることがあります。

そのため、宿に戻る余裕がある場合にはウエストポーチに入れ替えることがあります。(ウエストポーチにはスマホバッテリーを入れる)

マイバッグ

カンファレンスとかだとノベリティをよく貰うのでトートバックを持って行って貰ったノベリティを入れるようにしています。

esa.booth.pm

このesaのトートバッグは普段の買い物にも使っていますが大きくて丈夫なのでむっちゃ便利です。(ステマ

ちなみにこういう折りたたみ式のマイバッグも持っていて、こちらはウエストポーチに入れています。

栗アイコンシール

名札に貼る用

タオル

ライブだと汗をかくのでマフラータオルを持って行ってます。

痛バ(痛バッグ)

こういうやつ。

dic.pixiv.net

ライブとかだと手提げの痛バをよく見るのですが自分はリュックの方が慣れているのでリュック型を利用。

この手の痛バはいくつか買ったけど最終的にこれに落ち着きました。

www.elecom.co.jp

缶バッジの面は隠せるので電車とかでも普通に使えて便利。

ぬい(ぬいぐるみ)

ライブには ぬいを連れてく オタクです(一句)

ライブだと両手でペンライトを持ちたいため、ぬいぐるみを首からぶら下げるためにこういうバッグを使っています。

item.rakuten.co.jp

YARDで継承関係を明示的に伝えたい

こないだgemを作ってて調べたやつのメモ。

前置き

例えば下記のように Hashie::Mash を継承した Pixela::Response があるとします

module Pixela
  require "hashie/mash"

  # Pixela API response
  #
  # @see https://www.rubydoc.info/gems/hashie/Hashie/Hash
  # @see https://www.rubydoc.info/gems/hashie/Hashie/Mash
  class Response < Hashie::Mash
    disable_warnings
  end
end

Hashie::Mash はさらに Hashie::HashHash を継承しているため *1、実際には「 Pixela::Response < Hashie::Mash < Hashie::Hash < Hash < Object」という継承関係になります。

これを YARD でリファレンスを生成した場合下記のように、「 Pixela::Response < Hashie::Mash < Object」という継承関係になってしまいます。

これはYARDが Hashie::Mash の実装を知らないためなんですが、3rd party製のgemの継承関係をどうやってYARDに伝えればいいか困ったので調べました。

解決方法:@!parse で書く

@!parse *2 を使うとYARDのコメントの中だけで有効なRubyのコードを書けるので、そこで外部のgemの最低限のクラス定義を書いてやれば表示されるようになります。

# @!parse
#   module Hashie
#     # @see https://www.rubydoc.info/gems/hashie/Hashie/Hash
#     class Hash < ::Hash
#     end
#
#     # @see https://www.rubydoc.info/gems/hashie/Hashie/Mash
#     class Mash < Hash
#     end
#   end

module Pixela
  require "hashie/mash"

  # Pixela API response
  #
  # @see https://www.rubydoc.info/gems/hashie/Hashie/Hash
  # @see https://www.rubydoc.info/gems/hashie/Hashie/Mash
  class Response < Hashie::Mash
    disable_warnings
  end
end

moduleの外側に書くのがポイントで、 moduleの内側に書くと class Pixela::Hashie::Mash のようなクラスのリファレンスが作られたので、 @!parse はスコープを解釈してるらしいです。

実際のパッチとYARDで生成されたリファレンスは下記