Skip to content

Commit fba8a7f

Browse files
limit7412claude
andcommitted
chore: add tooling and tests, drop dead CI config (Phase 3)
- add ameba 1.6 as a development dependency and satisfy its lints - fix broken spec_helper (required a non-existent file) and replace the placeholder spec with model unit tests (Subject#color/#update?/#comment_url, Notification#mention?, JSON parsing, Slack serialization) - add GitHub Actions CI running format check / ameba / spec - remove obsolete .travis.yml; gitignore built bin/ refs #84 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent bbc54ea commit fba8a7f

11 files changed

Lines changed: 185 additions & 27 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: ci
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request:
7+
8+
jobs:
9+
check:
10+
name: format / lint / spec
11+
runs-on: ubuntu-24.04-arm
12+
steps:
13+
- name: checkout
14+
uses: actions/checkout@v4
15+
16+
- name: install crystal
17+
uses: crystal-lang/install-crystal@v1
18+
with:
19+
crystal: latest
20+
21+
- name: install shards
22+
run: shards install
23+
24+
- name: check format
25+
run: crystal tool format --check
26+
27+
- name: lint with ameba
28+
run: ./bin/ameba
29+
30+
- name: run specs
31+
run: crystal spec

‎.gitignore‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ jspm_packages
66
.serverless
77

88
bootstrap
9+
bin
910
lib
1011
env.yml
11-
12-
.idea/
12+
13+
.idea/

‎.travis.yml‎

Lines changed: 0 additions & 6 deletions
This file was deleted.

‎shard.lock‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
version: 1.0
1+
version: 2.0
22
shards:
3-
clim:
4-
github: at-grandpa/clim
5-
version: 0.4.1
3+
ameba:
4+
git: https://github.com/crystal-ameba/ameba.git
5+
version: 1.6.4
66

‎shard.yml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,9 @@ targets:
1010

1111
crystal: ">= 1.20.0"
1212

13+
development_dependencies:
14+
ameba:
15+
github: crystal-ameba/ameba
16+
version: ~> 1.6
17+
1318
license: MIT

‎spec/github/models_spec.cr‎

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
require "../spec_helper"
2+
3+
private def subject_from(type : String, url = "", latest_comment_url = "")
4+
Github::Subject.from_json({
5+
type: type,
6+
title: "title",
7+
url: url,
8+
latest_comment_url: latest_comment_url,
9+
}.to_json)
10+
end
11+
12+
describe Github::Subject do
13+
describe "#update?" do
14+
it "is true for tracked subject types" do
15+
[
16+
Github::Subject::Type::PULL_REQUEST,
17+
Github::Subject::Type::ISSUE,
18+
Github::Subject::Type::COMMIT,
19+
Github::Subject::Type::DISCUSSION,
20+
].each do |type|
21+
subject_from(type).update?.should be_true
22+
end
23+
end
24+
25+
it "is false for unknown subject types" do
26+
subject_from("Release").update?.should be_false
27+
end
28+
end
29+
30+
describe "#color" do
31+
it "returns a distinct color per known type" do
32+
subject_from(Github::Subject::Type::PULL_REQUEST).color.should eq "#F6CEE3"
33+
subject_from(Github::Subject::Type::ISSUE).color.should eq "#A9D0F5"
34+
subject_from(Github::Subject::Type::COMMIT).color.should eq "#f5d7a9"
35+
subject_from(Github::Subject::Type::DISCUSSION).color.should eq "#7fffd4"
36+
end
37+
38+
it "falls back to a default color for unknown types" do
39+
subject_from("Release").color.should eq "#D8D8D8"
40+
end
41+
end
42+
43+
describe "#comment_url" do
44+
it "prefers latest_comment_url when present" do
45+
subject = subject_from("Issue", url: "u", latest_comment_url: "c")
46+
subject.comment_url.should eq "c"
47+
end
48+
49+
it "falls back to url when latest_comment_url is blank" do
50+
subject = subject_from("Issue", url: "u", latest_comment_url: "")
51+
subject.comment_url.should eq "u"
52+
end
53+
end
54+
end
55+
56+
describe Github::Notification do
57+
describe "#mention?" do
58+
it "is true for reasons that mention the user" do
59+
Github::Notification::MENTION_REASONS.each do |reason|
60+
notification_from(reason).mention?.should be_true
61+
end
62+
end
63+
64+
it "is false for non-mention reasons" do
65+
notification_from("subscribed").mention?.should be_false
66+
notification_from("ci_activity").mention?.should be_false
67+
end
68+
end
69+
70+
it "parses a GitHub notifications API payload" do
71+
notifications = Array(Github::Notification).from_json(NOTIFICATIONS_FIXTURE)
72+
notifications.size.should eq 1
73+
74+
notification = notifications.first
75+
notification.reason.should eq "mention"
76+
notification.subject.type.should eq "Issue"
77+
notification.subject.title.should eq "Spurious failure"
78+
notification.repository.full_name.should eq "octocat/Hello-World"
79+
notification.mention?.should be_true
80+
end
81+
end
82+
83+
private def notification_from(reason : String)
84+
Github::Notification.from_json({
85+
reason: reason,
86+
subject: {type: "Issue", title: "title"},
87+
repository: {owner: {login: "octocat"}},
88+
}.to_json)
89+
end
90+
91+
NOTIFICATIONS_FIXTURE = <<-JSON
92+
[
93+
{
94+
"reason": "mention",
95+
"subject": {
96+
"title": "Spurious failure",
97+
"url": "https://api.github.com/repos/octocat/Hello-World/issues/1",
98+
"latest_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments/1",
99+
"type": "Issue"
100+
},
101+
"repository": {
102+
"full_name": "octocat/Hello-World",
103+
"html_url": "https://github.com/octocat/Hello-World",
104+
"owner": {
105+
"login": "octocat",
106+
"avatar_url": "https://github.com/images/error/octocat.gif",
107+
"html_url": "https://github.com/octocat"
108+
}
109+
},
110+
"subscription_url": "https://api.github.com/notifications/threads/1/subscription"
111+
}
112+
]
113+
JSON

‎spec/github_notifications_slack_spec.cr‎

Lines changed: 0 additions & 9 deletions
This file was deleted.

‎spec/slack/models_spec.cr‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
require "../spec_helper"
2+
3+
describe Slack::Attachment do
4+
it "omits unset fields when serialized" do
5+
json = Slack::Attachment.new(text: "hello", color: "#000000").to_json
6+
parsed = JSON.parse(json)
7+
8+
parsed["text"].should eq "hello"
9+
parsed["color"].should eq "#000000"
10+
parsed.as_h.has_key?("title").should be_false
11+
end
12+
end
13+
14+
describe Slack::Post do
15+
it "wraps attachments under an attachments key" do
16+
post = Slack::Post.new([Slack::Attachment.new(text: "a")])
17+
parsed = JSON.parse(post.to_json)
18+
19+
parsed["attachments"].as_a.size.should eq 1
20+
parsed["attachments"][0]["text"].should eq "a"
21+
end
22+
end

‎spec/spec_helper.cr‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
require "spec"
2-
require "../src/github_notifications_slack"
2+
require "../src/github/models"
3+
require "../src/slack/models"

‎src/main.cr‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ Serverless::Lambda.handler "github_notifications_slack" do |_|
1919
slack_repo = Slack::PostRepository.new WEBHOOK_URL
2020

2121
Notify::Usecase.new(github_repo, github_uc, slack_repo).check_notifications
22-
rescue err
22+
rescue error
2323
alert_repo = Slack::PostRepository.new ALERT_WEBHOOK_URL
24-
Error::Usecase.new(alert_repo, SLACK_ID, APP_ENV).alert err
25-
raise err
24+
Error::Usecase.new(alert_repo, SLACK_ID, APP_ENV).alert error
25+
raise error
2626
end
2727
end

0 commit comments

Comments
 (0)