From 076c4d78700cef40bf36f79a46c35f016095ae4c Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 29 Aug 2026 07:57:12 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20release=20=E9=80=9A=E7=9F=A5=E3=81=AE?= =?UTF-8?q?=E6=9C=AC=E6=96=87=E3=82=92=E5=8F=96=E5=BE=97=E3=81=A7=E3=81=8D?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Release の通知だけ本文が出ていなかった(issue #121)。原因は 2 つある。 ひとつは投稿者のキーの違い。GitHub の Release オブジェクトは投稿者を author に 入れるが、Github::Comment は user を必須にしていた。そのため Release の応答は JSON の解析ごと失敗し、find_comment_by_url の rescue に落ちて本文が 「(本文を取得できませんでした)」に置き換わっていた。user と author の どちらも nilable で受け、表示に使う投稿者は poster にまとめる。 もうひとつは本文取得先の判定。BODY_TYPES に Release が無いため、通知に latest_comment_url が入らない場合は comment_url が空になり、本文を取りに 行かなくなっていた。Release も subject.url を取得すればリリースノートが 返るので、BODY_TYPES に加える。 色は変えていない。Release は従来どおり既定色のままにする。 Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01SmoDC7XRgDx1AcWumgv3Uq --- spec/github/models_spec.cr | 42 +++++++++++++++++++++++++++++++++++++ spec/github/usecase_spec.cr | 27 ++++++++++++++++++++++++ src/github/models.cr | 18 ++++++++++++++-- src/github/usecase.cr | 6 +++--- 4 files changed, 88 insertions(+), 5 deletions(-) diff --git a/spec/github/models_spec.cr b/spec/github/models_spec.cr index e353faa..b32fd5a 100644 --- a/spec/github/models_spec.cr +++ b/spec/github/models_spec.cr @@ -59,6 +59,12 @@ describe Github::Subject do it "still uses latest_comment_url even for non-body types" do subject_from("Commit", url: "u", latest_comment_url: "c").comment_url.should eq "c" end + + # Release は subject.url を取得するとリリースノートが返る(issue #121)。 + it "falls back to url for a release when latest_comment_url is blank" do + subject = subject_from("Release", url: "https://api.github.com/repos/o/r/releases/1") + subject.comment_url.should eq "https://api.github.com/repos/o/r/releases/1" + end end describe "#commented?" do @@ -335,6 +341,42 @@ describe Github::Comment do Github::Comment.new(nil).commented?.should be_false end end + + # Release の応答は投稿者を author に入れる。user を必須にしていたころは解析ごと + # 失敗し、本文が「取得できませんでした」に倒れていた(issue #121)。 + describe "#poster" do + it "parses a release payload and keeps its body" do + comment = Github::Comment.from_json(release_payload) + + comment.body.should eq "リリースノート本文" + comment.poster.login.should eq "octocat" + end + + it "prefers the comment user over the author" do + json = {user: {login: "commenter"}, author: {login: "releaser"}, body: "b"}.to_json + Github::Comment.from_json(json).poster.login.should eq "commenter" + end + + it "falls back to an empty user when the payload has neither" do + Github::Comment.from_json({body: "b"}.to_json).poster.login.should be_nil + end + + it "returns an empty user for a locally built comment" do + Github::Comment.new("b").poster.login.should be_nil + end + end +end + +# GitHub の Release オブジェクト。投稿者は user ではなく author に入る。 +private def release_payload + { + url: "https://api.github.com/repos/o/r/releases/1", + html_url: "https://github.com/o/r/releases/tag/v1.2.3", + author: {login: "octocat", avatar_url: "https://example.com/a.png"}, + tag_name: "v1.2.3", + name: "v1.2.3", + body: "リリースノート本文", + }.to_json end private def notification_with(url = "", repo_html_url : String? = nil) diff --git a/spec/github/usecase_spec.cr b/spec/github/usecase_spec.cr index 847b644..f0fc346 100644 --- a/spec/github/usecase_spec.cr +++ b/spec/github/usecase_spec.cr @@ -51,6 +51,18 @@ private def subject_detail(comments : Int32? = nil, review_comments : Int32? = n }.to_json) end +# GitHub の Release オブジェクト。投稿者は user ではなく author に入る。 +private def release_payload + { + url: "https://api.github.com/repos/octocat/Hello-World/releases/1", + html_url: "https://github.com/octocat/Hello-World/releases/tag/v1.2.3", + author: {login: "octocat", avatar_url: "https://example.com/a.png"}, + tag_name: "v1.2.3", + name: "v1.2.3", + body: "リリースノート本文", + }.to_json +end + private def build(notify, comment) Github::Usecase.new(StubRepo.new(comment)).build_message(notify) end @@ -107,6 +119,21 @@ describe Github::Usecase do it "leaves text nil when there is no comment body" do build(notification, comment(body: nil)).text.should be_nil end + + # Release は投稿者が author に入るため、user を必須にしていたころは応答の解析に + # 失敗し、本文が「取得できませんでした」になっていた(issue #121)。 + it "keeps the release notes and author of a release notification" do + notify = notification( + url: "https://api.github.com/repos/octocat/Hello-World/releases/1", + reason: "subscribed", + type: Github::Subject::Type::RELEASE, + ) + message = build(notify, Github::Comment.from_json(release_payload)) + + message.text.should eq "リリースノート本文" + message.author_name.should eq "octocat" + message.title_link.should eq "https://github.com/octocat/Hello-World/releases/tag/v1.2.3" + end end describe "#build_message mention" do diff --git a/src/github/models.cr b/src/github/models.cr index 43f1efd..2ef8d3a 100644 --- a/src/github/models.cr +++ b/src/github/models.cr @@ -184,6 +184,7 @@ module Github ISSUE = "Issue" COMMIT = "Commit" DISCUSSION = "Discussion" + RELEASE = "Release" end UPDATE_TYPES = { @@ -207,6 +208,10 @@ module Github BODY_TYPES = { Type::PULL_REQUEST, Type::ISSUE, + # Release も subject.url を取得すると body(リリースノート)が返る。 + # 通知に latest_comment_url が入らない場合でも本文を出せるようにする + # (issue #121)。 + Type::RELEASE, } def update? : Bool @@ -278,7 +283,11 @@ module Github class Comment include JSON::Serializable - getter user : User + # 投稿者。コメントや Issue / PR では user だが、Release では author に入る。 + # 必須にすると Release の応答が丸ごと解析エラーになり、本文まで + # 「取得できませんでした」に倒れるため、どちらも nilable で受ける(issue #121)。 + getter user : User? + getter author : User? getter html_url : String? getter body : String? # スレッドのコメント数。subject 本体を取得したときだけ入り、コメント @@ -288,7 +297,12 @@ module Github getter review_comments : Int32? def initialize(@body) - @user = User.new + end + + # 表示に使う投稿者。どちらのキーも無い応答では空の User を返し、名前も + # アイコンも付けずに本文だけを出す。 + def poster : User + user || author || User.new end # スレッドにコメントが 1 件以上付いているか(issue #116)。 diff --git a/src/github/usecase.cr b/src/github/usecase.cr index 9e0188d..f5b8d62 100644 --- a/src/github/usecase.cr +++ b/src/github/usecase.cr @@ -18,9 +18,9 @@ module Github # 投稿の区切りは reason だけで決め、CI によるメンション抑止は反映しない # (issue #120。理由は Notify::Message#important? のコメント)。 important: notify.mention?, - author_name: comment.user.login, - author_icon: comment.user.avatar_url, - author_link: comment.user.html_url, + author_name: comment.poster.login, + author_icon: comment.poster.avatar_url, + author_link: comment.poster.html_url, # コメントが無いスレッドでは comment は subject 本体(PR / Issue)になる。 # その中のコメント数を文言の切り替え判定に使う(issue #116)。 pretext: notify.pretext(comment),