codeclimate-services 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/.travis.yml +13 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +121 -0
- data/Rakefile +11 -0
- data/bin/bundler +16 -0
- data/bin/coderay +16 -0
- data/bin/nokogiri +16 -0
- data/bin/pry +16 -0
- data/bin/rake +16 -0
- data/codeclimate-services.gemspec +29 -0
- data/config/cacert.pem +4026 -0
- data/config/load.rb +4 -0
- data/lib/axiom/types/password.rb +7 -0
- data/lib/cc/formatters/linked_formatter.rb +60 -0
- data/lib/cc/formatters/plain_formatter.rb +36 -0
- data/lib/cc/formatters/snapshot_formatter.rb +101 -0
- data/lib/cc/formatters/ticket_formatter.rb +27 -0
- data/lib/cc/helpers/coverage_helper.rb +25 -0
- data/lib/cc/helpers/issue_helper.rb +9 -0
- data/lib/cc/helpers/quality_helper.rb +44 -0
- data/lib/cc/helpers/vulnerability_helper.rb +31 -0
- data/lib/cc/presenters/github_pull_requests_presenter.rb +54 -0
- data/lib/cc/service/config.rb +4 -0
- data/lib/cc/service/formatter.rb +34 -0
- data/lib/cc/service/helper.rb +54 -0
- data/lib/cc/service/http.rb +87 -0
- data/lib/cc/service/invocation/invocation_chain.rb +15 -0
- data/lib/cc/service/invocation/with_error_handling.rb +45 -0
- data/lib/cc/service/invocation/with_metrics.rb +37 -0
- data/lib/cc/service/invocation/with_retries.rb +17 -0
- data/lib/cc/service/invocation/with_return_values.rb +18 -0
- data/lib/cc/service/invocation.rb +57 -0
- data/lib/cc/service/response_check.rb +42 -0
- data/lib/cc/service.rb +127 -0
- data/lib/cc/services/asana.rb +90 -0
- data/lib/cc/services/campfire.rb +55 -0
- data/lib/cc/services/flowdock.rb +61 -0
- data/lib/cc/services/github_issues.rb +80 -0
- data/lib/cc/services/github_pull_requests.rb +210 -0
- data/lib/cc/services/hipchat.rb +57 -0
- data/lib/cc/services/jira.rb +93 -0
- data/lib/cc/services/lighthouse.rb +79 -0
- data/lib/cc/services/pivotal_tracker.rb +78 -0
- data/lib/cc/services/slack.rb +124 -0
- data/lib/cc/services/version.rb +5 -0
- data/lib/cc/services.rb +9 -0
- data/pull_request_test.rb +47 -0
- data/service_test.rb +86 -0
- data/test/asana_test.rb +85 -0
- data/test/axiom/types/password_test.rb +22 -0
- data/test/campfire_test.rb +144 -0
- data/test/fixtures.rb +68 -0
- data/test/flowdock_test.rb +148 -0
- data/test/formatters/snapshot_formatter_test.rb +47 -0
- data/test/github_issues_test.rb +96 -0
- data/test/github_pull_requests_test.rb +293 -0
- data/test/helper.rb +50 -0
- data/test/hipchat_test.rb +130 -0
- data/test/invocation_error_handling_test.rb +51 -0
- data/test/invocation_return_values_test.rb +21 -0
- data/test/invocation_test.rb +167 -0
- data/test/jira_test.rb +80 -0
- data/test/lighthouse_test.rb +74 -0
- data/test/pivotal_tracker_test.rb +73 -0
- data/test/presenters/github_pull_requests_presenter_test.rb +49 -0
- data/test/service_test.rb +63 -0
- data/test/slack_test.rb +222 -0
- data/test/support/fake_logger.rb +11 -0
- data/test/with_metrics_test.rb +19 -0
- metadata +263 -0
data/service_test.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Ad-hoc script for sending the test event to service classes
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# $ <SERVICE>_<CONFIG_ATTR_1>="..." \
|
8
|
+
# <SERVICE>_<CONFIG_ATTR_2>="..." \
|
9
|
+
# ... ... bundle exec ruby service_test.rb
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
#
|
13
|
+
# $ SLACK_WEBHOOK_URL="http://..." bundle exec ruby service_test.rb
|
14
|
+
# $ GITHUBPULLREQUESTS_UPDATE_STATUS=false GITHUBPULLREQUESTS_ADD_COMMENT=true GITHUBPULLREQUESTS_OAUTH_TOKEN=06083a4a060d358ca709939b1f00645777661c44 bundle exec ruby service_test.rb
|
15
|
+
#
|
16
|
+
# Other Environment variables used:
|
17
|
+
#
|
18
|
+
# REPO_NAME Defaults to "App"
|
19
|
+
#
|
20
|
+
###
|
21
|
+
require 'cc/services'
|
22
|
+
CC::Service.load_services
|
23
|
+
|
24
|
+
class WithResponseLogging
|
25
|
+
def initialize(invocation)
|
26
|
+
@invocation = invocation
|
27
|
+
end
|
28
|
+
|
29
|
+
def call
|
30
|
+
@invocation.call.tap { |r| p r }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class ServiceTest
|
35
|
+
def initialize(klass, *params)
|
36
|
+
@klass = klass
|
37
|
+
@params = params
|
38
|
+
end
|
39
|
+
|
40
|
+
def test(payload = {})
|
41
|
+
config = {}
|
42
|
+
|
43
|
+
puts "-"*80
|
44
|
+
puts @klass
|
45
|
+
|
46
|
+
@params.each do |param|
|
47
|
+
if var = ENV[to_env_var(param)]
|
48
|
+
config[param] = var
|
49
|
+
else
|
50
|
+
puts " -> skipping"
|
51
|
+
return false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
puts " -> testing"
|
56
|
+
puts " -> #{config.inspect}"
|
57
|
+
print " => "
|
58
|
+
|
59
|
+
test_service(@klass, config, payload)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def to_env_var(param)
|
65
|
+
"#{@klass.to_s.split("::").last}_#{param}".upcase
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_service(klass, config, payload)
|
69
|
+
repo_name = ENV["REPO_NAME"] || "App"
|
70
|
+
|
71
|
+
service = klass.new(
|
72
|
+
config,
|
73
|
+
{ name: :test, repo_name: repo_name }.merge(payload)
|
74
|
+
)
|
75
|
+
|
76
|
+
CC::Service::Invocation.new(service) do |i|
|
77
|
+
i.wrap(WithResponseLogging)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
ServiceTest.new(CC::Service::Slack, :webhook_url).test
|
83
|
+
ServiceTest.new(CC::Service::Flowdock, :api_token).test
|
84
|
+
ServiceTest.new(CC::Service::Jira, :username, :password, :domain, :project_id).test
|
85
|
+
ServiceTest.new(CC::Service::Asana, :api_key, :workspace_id, :project_id).test
|
86
|
+
ServiceTest.new(CC::Service::GitHubPullRequests, :oauth_token, :update_status, :add_comment).test({ github_slug: "codeclimate/codeclimate" })
|
data/test/asana_test.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.expand_path('../helper', __FILE__)
|
2
|
+
|
3
|
+
class TestAsana < CC::Service::TestCase
|
4
|
+
def test_quality
|
5
|
+
assert_asana_receives(
|
6
|
+
event(:quality, to: "D", from: "C"),
|
7
|
+
"Refactor User from a D on Code Climate - https://codeclimate.com/repos/1/feed"
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_vulnerability
|
12
|
+
assert_asana_receives(
|
13
|
+
event(:vulnerability, vulnerabilities: [{
|
14
|
+
"warning_type" => "critical",
|
15
|
+
"location" => "app/user.rb line 120"
|
16
|
+
}]),
|
17
|
+
"New critical issue found in app/user.rb line 120 - https://codeclimate.com/repos/1/feed"
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_issue
|
22
|
+
payload = {
|
23
|
+
issue: {
|
24
|
+
"check_name" => "Style/LongLine",
|
25
|
+
"description" => "Line is too long [1000/80]"
|
26
|
+
},
|
27
|
+
constant_name: "foo.rb",
|
28
|
+
details_url: "http://example.com/repos/id/foo.rb#issue_123"
|
29
|
+
}
|
30
|
+
|
31
|
+
assert_asana_receives(
|
32
|
+
event(:issue, payload),
|
33
|
+
"Fix \"Style/LongLine\" issue in foo.rb",
|
34
|
+
"Line is too long [1000/80]\n\nhttp://example.com/repos/id/foo.rb#issue_123"
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_successful_post
|
39
|
+
@stubs.post '/api/1.0/tasks' do |env|
|
40
|
+
[200, {}, '{"data":{"id":"2"}}']
|
41
|
+
end
|
42
|
+
|
43
|
+
response = receive_event
|
44
|
+
|
45
|
+
assert_equal "2", response[:id]
|
46
|
+
assert_equal "https://app.asana.com/0/1/2", response[:url]
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_receive_test
|
50
|
+
@stubs.post '/api/1.0/tasks' do |env|
|
51
|
+
[200, {}, '{"data":{"id":"4"}}']
|
52
|
+
end
|
53
|
+
|
54
|
+
response = receive_event(name: "test")
|
55
|
+
|
56
|
+
assert_equal "Ticket <a href='https://app.asana.com/0/1/4'>4</a> created.", response[:message]
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def assert_asana_receives(event_data, name, notes = nil)
|
62
|
+
@stubs.post '/api/1.0/tasks' do |env|
|
63
|
+
body = JSON.parse(env[:body])
|
64
|
+
data = body["data"]
|
65
|
+
|
66
|
+
assert_equal "1", data["workspace"]
|
67
|
+
assert_equal "2", data["projects"].first
|
68
|
+
assert_equal "jim@asana.com", data["assignee"]
|
69
|
+
assert_equal name, data["name"]
|
70
|
+
assert_equal notes, data["notes"]
|
71
|
+
|
72
|
+
[200, {}, '{"data":{"id":4}}']
|
73
|
+
end
|
74
|
+
|
75
|
+
receive_event(event_data)
|
76
|
+
end
|
77
|
+
|
78
|
+
def receive_event(event_data = nil)
|
79
|
+
receive(
|
80
|
+
CC::Service::Asana,
|
81
|
+
{ api_key: "abc123", workspace_id: "1", project_id: "2", assignee: "jim@asana.com" },
|
82
|
+
event_data || event(:quality, to: "D", from: "C")
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path('../../../helper', __FILE__)
|
2
|
+
|
3
|
+
class Axiom::Types::PasswordTest < CC::Service::TestCase
|
4
|
+
class TestConfiguration < CC::Service::Config
|
5
|
+
attribute :password_attribute, Password
|
6
|
+
attribute :string_attribute, String
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_password_type_inference
|
10
|
+
assert_equal(
|
11
|
+
Axiom::Types::Password,
|
12
|
+
TestConfiguration.attribute_set[:password_attribute].type
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_string_type_inference
|
17
|
+
assert_equal(
|
18
|
+
Axiom::Types::String,
|
19
|
+
TestConfiguration.attribute_set[:string_attribute].type
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require File.expand_path('../helper', __FILE__)
|
2
|
+
|
3
|
+
class TestCampfire < CC::Service::TestCase
|
4
|
+
def test_config
|
5
|
+
assert_raises CC::Service::ConfigurationError do
|
6
|
+
service(CC::Service::Campfire, {}, {name: "test"})
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_test_hook
|
11
|
+
assert_campfire_receives(
|
12
|
+
{ name: "test", repo_name: "Rails" },
|
13
|
+
"[Code Climate][Rails] This is a test of the Campfire service hook"
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_coverage_improved
|
18
|
+
e = event(:coverage, to: 90.2, from: 80)
|
19
|
+
|
20
|
+
assert_campfire_receives(e, [
|
21
|
+
"[Code Climate][Example] :sunny:",
|
22
|
+
"Test coverage has improved to 90.2% (+10.2%).",
|
23
|
+
"(https://codeclimate.com/repos/1/feed)"
|
24
|
+
].join(" "))
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_coverage_declined
|
28
|
+
e = event(:coverage, to: 88.6, from: 94.6)
|
29
|
+
|
30
|
+
assert_campfire_receives(e, [
|
31
|
+
"[Code Climate][Example] :umbrella:",
|
32
|
+
"Test coverage has declined to 88.6% (-6.0%).",
|
33
|
+
"(https://codeclimate.com/repos/1/feed)"
|
34
|
+
].join(" "))
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_quality_improved
|
38
|
+
e = event(:quality, to: "A", from: "B")
|
39
|
+
|
40
|
+
assert_campfire_receives(e, [
|
41
|
+
"[Code Climate][Example] :sunny:",
|
42
|
+
"User has improved from a B to an A.",
|
43
|
+
"(https://codeclimate.com/repos/1/feed)"
|
44
|
+
].join(" "))
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_quality_declined
|
48
|
+
e = event(:quality, to: "D", from: "C")
|
49
|
+
|
50
|
+
assert_campfire_receives(e, [
|
51
|
+
"[Code Climate][Example] :umbrella:",
|
52
|
+
"User has declined from a C to a D.",
|
53
|
+
"(https://codeclimate.com/repos/1/feed)"
|
54
|
+
].join(" "))
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_single_vulnerability
|
58
|
+
e = event(:vulnerability, vulnerabilities: [
|
59
|
+
{ "warning_type" => "critical" }
|
60
|
+
])
|
61
|
+
|
62
|
+
assert_campfire_receives(e, [
|
63
|
+
"[Code Climate][Example]",
|
64
|
+
"New critical issue found.",
|
65
|
+
"Details: https://codeclimate.com/repos/1/feed"
|
66
|
+
].join(" "))
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_single_vulnerability_with_location
|
70
|
+
e = event(:vulnerability, vulnerabilities: [{
|
71
|
+
"warning_type" => "critical",
|
72
|
+
"location" => "app/user.rb line 120"
|
73
|
+
}])
|
74
|
+
|
75
|
+
assert_campfire_receives(e, [
|
76
|
+
"[Code Climate][Example]",
|
77
|
+
"New critical issue found",
|
78
|
+
"in app/user.rb line 120.",
|
79
|
+
"Details: https://codeclimate.com/repos/1/feed"
|
80
|
+
].join(" "))
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_multiple_vulnerabilities
|
84
|
+
e = event(:vulnerability, warning_type: "critical", vulnerabilities: [{
|
85
|
+
"warning_type" => "unused",
|
86
|
+
"location" => "unused"
|
87
|
+
}, {
|
88
|
+
"warning_type" => "unused",
|
89
|
+
"location" => "unused"
|
90
|
+
}])
|
91
|
+
|
92
|
+
assert_campfire_receives(e, [
|
93
|
+
"[Code Climate][Example]",
|
94
|
+
"2 new critical issues found.",
|
95
|
+
"Details: https://codeclimate.com/repos/1/feed"
|
96
|
+
].join(" "))
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_receive_test
|
100
|
+
@stubs.post request_url do |env|
|
101
|
+
[200, {}, '']
|
102
|
+
end
|
103
|
+
|
104
|
+
response = receive_event(name: "test")
|
105
|
+
|
106
|
+
assert_equal "Test message sent", response[:message]
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def speak_uri
|
112
|
+
"https://#{subdomain}.campfirenow.com#{request_url}"
|
113
|
+
end
|
114
|
+
|
115
|
+
def request_url
|
116
|
+
"/room/#{room}/speak.json"
|
117
|
+
end
|
118
|
+
|
119
|
+
def subdomain
|
120
|
+
"sub"
|
121
|
+
end
|
122
|
+
|
123
|
+
def room
|
124
|
+
"123"
|
125
|
+
end
|
126
|
+
|
127
|
+
def assert_campfire_receives(event_data, expected_body)
|
128
|
+
@stubs.post request_url do |env|
|
129
|
+
body = JSON.parse(env[:body])
|
130
|
+
assert_equal expected_body, body["message"]["body"]
|
131
|
+
[200, {}, '']
|
132
|
+
end
|
133
|
+
|
134
|
+
receive_event(event_data)
|
135
|
+
end
|
136
|
+
|
137
|
+
def receive_event(event_data = nil)
|
138
|
+
receive(
|
139
|
+
CC::Service::Campfire,
|
140
|
+
{ token: "token", subdomain: subdomain, room_id: room},
|
141
|
+
event_data || event(:quality, to: "D", from: "C")
|
142
|
+
)
|
143
|
+
end
|
144
|
+
end
|
data/test/fixtures.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
class EventFixtures
|
2
|
+
attr_reader :options
|
3
|
+
|
4
|
+
REMEDIATIONS = {
|
5
|
+
"A" => 0,
|
6
|
+
"B" => 10,
|
7
|
+
"C" => 15,
|
8
|
+
"D" => 20,
|
9
|
+
"F" => 25,
|
10
|
+
}
|
11
|
+
|
12
|
+
def initialize(options)
|
13
|
+
@options = {
|
14
|
+
repo_name: "Example",
|
15
|
+
details_url: "https://codeclimate.com/repos/1/feed",
|
16
|
+
compare_url: "https://codeclimate.com/repos/1/compare",
|
17
|
+
}.merge(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Options: to, from
|
21
|
+
def coverage
|
22
|
+
to = options.delete(:to)
|
23
|
+
from = options.delete(:from)
|
24
|
+
delta = (to - from).round(1)
|
25
|
+
|
26
|
+
options.merge(
|
27
|
+
name: "coverage",
|
28
|
+
covered_percent: to,
|
29
|
+
previous_covered_percent: from,
|
30
|
+
covered_percent_delta: delta
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Options: to, from
|
35
|
+
def quality
|
36
|
+
to = options.delete(:to)
|
37
|
+
from = options.delete(:from)
|
38
|
+
|
39
|
+
options.merge(
|
40
|
+
name: "quality",
|
41
|
+
constant_name: "User",
|
42
|
+
rating: to,
|
43
|
+
previous_rating: from,
|
44
|
+
remediation_cost: REMEDIATIONS[to],
|
45
|
+
previous_remediation_cost: REMEDIATIONS[from]
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Options: warning_type, vulnerabilities
|
50
|
+
def vulnerability
|
51
|
+
options.merge(name: "vulnerability")
|
52
|
+
end
|
53
|
+
|
54
|
+
def issue
|
55
|
+
options.merge(name: "issue")
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def event(name, options = {})
|
61
|
+
fixtures = EventFixtures.new(options)
|
62
|
+
|
63
|
+
if fixtures.respond_to?(name)
|
64
|
+
fixtures.send(name)
|
65
|
+
else
|
66
|
+
raise ArgumentError, "No such fixture: #{name}"
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require File.expand_path('../helper', __FILE__)
|
2
|
+
|
3
|
+
class TestFlowdock < CC::Service::TestCase
|
4
|
+
def test_valid_project_parameter
|
5
|
+
@stubs.post '/v1/messages/team_inbox/token' do |env|
|
6
|
+
body = Hash[URI.decode_www_form(env[:body])]
|
7
|
+
assert_equal "Exampleorg", body["project"]
|
8
|
+
[200, {}, '']
|
9
|
+
end
|
10
|
+
|
11
|
+
receive(
|
12
|
+
CC::Service::Flowdock,
|
13
|
+
{ api_token: "token" },
|
14
|
+
{ name: "test", repo_name: "Example.org" }
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_test_hook
|
19
|
+
assert_flowdock_receives(
|
20
|
+
"Test",
|
21
|
+
{ name: "test", repo_name: "Example" },
|
22
|
+
"This is a test of the Flowdock service hook"
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_coverage_improved
|
27
|
+
e = event(:coverage, to: 90.2, from: 80)
|
28
|
+
|
29
|
+
assert_flowdock_receives("Coverage", e, [
|
30
|
+
"<a href=\"https://codeclimate.com/repos/1/feed\">Test coverage</a>",
|
31
|
+
"has improved to 90.2% (+10.2%)",
|
32
|
+
"(<a href=\"https://codeclimate.com/repos/1/compare\">Compare</a>)"
|
33
|
+
].join(" "))
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_coverage_declined
|
37
|
+
e = event(:coverage, to: 88.6, from: 94.6)
|
38
|
+
|
39
|
+
assert_flowdock_receives("Coverage", e, [
|
40
|
+
"<a href=\"https://codeclimate.com/repos/1/feed\">Test coverage</a>",
|
41
|
+
"has declined to 88.6% (-6.0%)",
|
42
|
+
"(<a href=\"https://codeclimate.com/repos/1/compare\">Compare</a>)"
|
43
|
+
].join(" "))
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_quality_improved
|
47
|
+
e = event(:quality, to: "A", from: "B")
|
48
|
+
|
49
|
+
assert_flowdock_receives("Quality", e, [
|
50
|
+
"<a href=\"https://codeclimate.com/repos/1/feed\">User</a>",
|
51
|
+
"has improved from a B to an A",
|
52
|
+
"(<a href=\"https://codeclimate.com/repos/1/compare\">Compare</a>)"
|
53
|
+
].join(" "))
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_quality_declined
|
57
|
+
e = event(:quality, to: "D", from: "C")
|
58
|
+
|
59
|
+
assert_flowdock_receives("Quality", e, [
|
60
|
+
"<a href=\"https://codeclimate.com/repos/1/feed\">User</a>",
|
61
|
+
"has declined from a C to a D",
|
62
|
+
"(<a href=\"https://codeclimate.com/repos/1/compare\">Compare</a>)"
|
63
|
+
].join(" "))
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_single_vulnerability
|
67
|
+
e = event(:vulnerability, vulnerabilities: [
|
68
|
+
{ "warning_type" => "critical" }
|
69
|
+
])
|
70
|
+
|
71
|
+
assert_flowdock_receives("Vulnerability", e, [
|
72
|
+
"New <a href=\"https://codeclimate.com/repos/1/feed\">critical</a>",
|
73
|
+
"issue found",
|
74
|
+
].join(" "))
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_single_vulnerability_with_location
|
78
|
+
e = event(:vulnerability, vulnerabilities: [{
|
79
|
+
"warning_type" => "critical",
|
80
|
+
"location" => "app/user.rb line 120"
|
81
|
+
}])
|
82
|
+
|
83
|
+
assert_flowdock_receives("Vulnerability", e, [
|
84
|
+
"New <a href=\"https://codeclimate.com/repos/1/feed\">critical</a>",
|
85
|
+
"issue found in app/user.rb line 120",
|
86
|
+
].join(" "))
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_multiple_vulnerabilities
|
90
|
+
e = event(:vulnerability, warning_type: "critical", vulnerabilities: [{
|
91
|
+
"warning_type" => "unused",
|
92
|
+
"location" => "unused"
|
93
|
+
}, {
|
94
|
+
"warning_type" => "unused",
|
95
|
+
"location" => "unused"
|
96
|
+
}])
|
97
|
+
|
98
|
+
assert_flowdock_receives("Vulnerability", e, [
|
99
|
+
"2 new <a href=\"https://codeclimate.com/repos/1/feed\">critical</a>",
|
100
|
+
"issues found",
|
101
|
+
].join(" "))
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_receive_test
|
105
|
+
@stubs.post request_url do |env|
|
106
|
+
[200, {}, '']
|
107
|
+
end
|
108
|
+
|
109
|
+
response = receive_event(name: "test", repo_name: "foo")
|
110
|
+
|
111
|
+
assert_equal "Test message sent", response[:message]
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def endpoint_url
|
117
|
+
"https://api.flowdock.com#{request_url}"
|
118
|
+
end
|
119
|
+
|
120
|
+
def request_url
|
121
|
+
"/v1/messages/team_inbox/#{token}"
|
122
|
+
end
|
123
|
+
|
124
|
+
def token
|
125
|
+
"token"
|
126
|
+
end
|
127
|
+
|
128
|
+
def assert_flowdock_receives(subject, event_data, expected_body)
|
129
|
+
@stubs.post request_url do |env|
|
130
|
+
body = Hash[URI.decode_www_form(env[:body])]
|
131
|
+
assert_equal "Code Climate", body["source"]
|
132
|
+
assert_equal "hello@codeclimate.com", body["from_address"]
|
133
|
+
assert_equal "Code Climate", body["from_name"]
|
134
|
+
assert_equal "html", body["format"]
|
135
|
+
assert_equal subject, body["subject"]
|
136
|
+
assert_equal "Example", body["project"]
|
137
|
+
assert_equal expected_body, body["content"]
|
138
|
+
assert_equal "https://codeclimate.com", body["link"]
|
139
|
+
[200, {}, '']
|
140
|
+
end
|
141
|
+
|
142
|
+
receive_event(event_data)
|
143
|
+
end
|
144
|
+
|
145
|
+
def receive_event(event_data = nil)
|
146
|
+
receive(CC::Service::Flowdock, { api_token: "token" }, event_data || event(:quality, from: "D", to: "C"))
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "helper"
|
2
|
+
|
3
|
+
class TestSnapshotFormatter < Test::Unit::TestCase
|
4
|
+
def described_class
|
5
|
+
CC::Formatters::SnapshotFormatter::Base
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_quality_alert_with_new_constants
|
9
|
+
f = described_class.new({"new_constants" => [{"to" => {"rating" => "D"}}], "changed_constants" => []})
|
10
|
+
refute_nil f.alert_constants_payload
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_quality_alert_with_decreased_constants
|
14
|
+
f = described_class.new({"new_constants" => [],
|
15
|
+
"changed_constants" => [{"to" => {"rating" => "D"}, "from" => {"rating" => "A"}}]
|
16
|
+
})
|
17
|
+
refute_nil f.alert_constants_payload
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_quality_improvements_with_better_ratings
|
21
|
+
f = described_class.new({"new_constants" => [],
|
22
|
+
"changed_constants" => [{"to" => {"rating" => "A"}, "from" => {"rating" => "D"}}]
|
23
|
+
})
|
24
|
+
refute_nil f.improved_constants_payload
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_nothing_set_without_changes
|
28
|
+
f = described_class.new({"new_constants" => [], "changed_constants" => []})
|
29
|
+
assert_nil f.alert_constants_payload
|
30
|
+
assert_nil f.improved_constants_payload
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_snapshot_formatter_test_with_relaxed_constraints
|
34
|
+
f = CC::Formatters::SnapshotFormatter::Sample.new({
|
35
|
+
"new_constants" => [{"name" => "foo", "to" => {"rating" => "A"}}, {"name" => "bar", "to" => {"rating" => "A"}}],
|
36
|
+
"changed_constants" => [
|
37
|
+
{"from" => {"rating" => "B"}, "to" => {"rating" => "C"}},
|
38
|
+
{"from" => {"rating" => "D"}, "to" => {"rating" => "D"}},
|
39
|
+
{"from" => {"rating" => "D"}, "to" => {"rating" => "D"}},
|
40
|
+
{"from" => {"rating" => "A"}, "to" => {"rating" => "B"}},
|
41
|
+
{"from" => {"rating" => "C"}, "to" => {"rating" => "B"}}
|
42
|
+
]})
|
43
|
+
|
44
|
+
refute_nil f.alert_constants_payload
|
45
|
+
refute_nil f.improved_constants_payload
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require File.expand_path('../helper', __FILE__)
|
2
|
+
|
3
|
+
class TestGitHubIssues < CC::Service::TestCase
|
4
|
+
def test_creation_success
|
5
|
+
id = 1234
|
6
|
+
number = 123
|
7
|
+
url = "https://github.com/#{project}/pulls/#{number}"
|
8
|
+
stub_http(request_url, [201, {}, %<{"id": #{id}, "number": #{number}, "html_url":"#{url}"}>])
|
9
|
+
|
10
|
+
response = receive_event
|
11
|
+
|
12
|
+
assert_equal id, response[:id]
|
13
|
+
assert_equal number, response[:number]
|
14
|
+
assert_equal url, response[:url]
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_quality
|
18
|
+
assert_github_receives(
|
19
|
+
event(:quality, to: "D", from: "C"),
|
20
|
+
"Refactor User from a D on Code Climate",
|
21
|
+
"https://codeclimate.com/repos/1/feed"
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_issue
|
26
|
+
payload = {
|
27
|
+
issue: {
|
28
|
+
"check_name" => "Style/LongLine",
|
29
|
+
"description" => "Line is too long [1000/80]"
|
30
|
+
},
|
31
|
+
constant_name: "foo.rb",
|
32
|
+
details_url: "http://example.com/repos/id/foo.rb#issue_123"
|
33
|
+
}
|
34
|
+
|
35
|
+
assert_github_receives(
|
36
|
+
event(:issue, payload),
|
37
|
+
"Fix \"Style/LongLine\" issue in foo.rb",
|
38
|
+
"Line is too long [1000/80]\n\nhttp://example.com/repos/id/foo.rb#issue_123"
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_vulnerability
|
43
|
+
assert_github_receives(
|
44
|
+
event(:vulnerability, vulnerabilities: [{
|
45
|
+
"warning_type" => "critical",
|
46
|
+
"location" => "app/user.rb line 120"
|
47
|
+
}]),
|
48
|
+
"New critical issue found in app/user.rb line 120",
|
49
|
+
"A critical vulnerability was found by Code Climate in app/user.rb line 120.\n\nhttps://codeclimate.com/repos/1/feed"
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_receive_test
|
54
|
+
@stubs.post request_url do |env|
|
55
|
+
[200, {}, '{"number": 2, "html_url": "http://foo.bar"}']
|
56
|
+
end
|
57
|
+
|
58
|
+
response = receive_event(name: "test")
|
59
|
+
|
60
|
+
assert_equal "Issue <a href='http://foo.bar'>#2</a> created.", response[:message]
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def project
|
66
|
+
"brynary/test_repo"
|
67
|
+
end
|
68
|
+
|
69
|
+
def oauth_token
|
70
|
+
"123"
|
71
|
+
end
|
72
|
+
|
73
|
+
def request_url
|
74
|
+
"repos/#{project}/issues"
|
75
|
+
end
|
76
|
+
|
77
|
+
def assert_github_receives(event_data, title, ticket_body)
|
78
|
+
@stubs.post request_url do |env|
|
79
|
+
body = JSON.parse(env[:body])
|
80
|
+
assert_equal "token #{oauth_token}", env[:request_headers]["Authorization"]
|
81
|
+
assert_equal title, body["title"]
|
82
|
+
assert_equal ticket_body, body["body"]
|
83
|
+
[200, {}, '{}']
|
84
|
+
end
|
85
|
+
|
86
|
+
receive_event(event_data)
|
87
|
+
end
|
88
|
+
|
89
|
+
def receive_event(event_data = nil)
|
90
|
+
receive(
|
91
|
+
CC::Service::GitHubIssues,
|
92
|
+
{ oauth_token: "123", project: project },
|
93
|
+
event_data || event(:quality, from: "D", to: "C")
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|