codebot 1.2.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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE.md +32 -0
  3. data/.github/ISSUE_TEMPLATE/formatter_issue.md +20 -0
  4. data/.github/PULL_REQUEST_TEMPLATE.md +13 -0
  5. data/.gitignore +10 -0
  6. data/.rspec +1 -0
  7. data/.rubocop.yml +11 -0
  8. data/.travis.yml +26 -0
  9. data/CODE_OF_CONDUCT.md +46 -0
  10. data/CONTRIBUTING.md +15 -0
  11. data/Gemfile +4 -0
  12. data/Gemfile.lock +75 -0
  13. data/LICENSE +21 -0
  14. data/README.md +230 -0
  15. data/Rakefile +29 -0
  16. data/bin/console +8 -0
  17. data/codebot.gemspec +49 -0
  18. data/exe/codebot +7 -0
  19. data/lib/codebot.rb +8 -0
  20. data/lib/codebot/channel.rb +134 -0
  21. data/lib/codebot/command_error.rb +17 -0
  22. data/lib/codebot/config.rb +125 -0
  23. data/lib/codebot/configuration_error.rb +17 -0
  24. data/lib/codebot/core.rb +76 -0
  25. data/lib/codebot/cryptography.rb +38 -0
  26. data/lib/codebot/event.rb +62 -0
  27. data/lib/codebot/ext/cinch/ssl_extensions.rb +37 -0
  28. data/lib/codebot/formatter.rb +242 -0
  29. data/lib/codebot/formatters.rb +109 -0
  30. data/lib/codebot/formatters/.rubocop.yml +2 -0
  31. data/lib/codebot/formatters/commit_comment.rb +43 -0
  32. data/lib/codebot/formatters/fork.rb +40 -0
  33. data/lib/codebot/formatters/gitlab_issue_hook.rb +56 -0
  34. data/lib/codebot/formatters/gitlab_job_hook.rb +77 -0
  35. data/lib/codebot/formatters/gitlab_merge_request_hook.rb +57 -0
  36. data/lib/codebot/formatters/gitlab_note_hook.rb +119 -0
  37. data/lib/codebot/formatters/gitlab_pipeline_hook.rb +51 -0
  38. data/lib/codebot/formatters/gitlab_push_hook.rb +83 -0
  39. data/lib/codebot/formatters/gitlab_wiki_page_hook.rb +56 -0
  40. data/lib/codebot/formatters/gollum.rb +67 -0
  41. data/lib/codebot/formatters/issue_comment.rb +41 -0
  42. data/lib/codebot/formatters/issues.rb +41 -0
  43. data/lib/codebot/formatters/ping.rb +79 -0
  44. data/lib/codebot/formatters/public.rb +30 -0
  45. data/lib/codebot/formatters/pull_request.rb +71 -0
  46. data/lib/codebot/formatters/pull_request_review_comment.rb +49 -0
  47. data/lib/codebot/formatters/push.rb +172 -0
  48. data/lib/codebot/formatters/watch.rb +38 -0
  49. data/lib/codebot/integration.rb +195 -0
  50. data/lib/codebot/integration_manager.rb +225 -0
  51. data/lib/codebot/ipc_client.rb +83 -0
  52. data/lib/codebot/ipc_server.rb +79 -0
  53. data/lib/codebot/irc_client.rb +102 -0
  54. data/lib/codebot/irc_connection.rb +156 -0
  55. data/lib/codebot/message.rb +37 -0
  56. data/lib/codebot/metadata.rb +15 -0
  57. data/lib/codebot/network.rb +240 -0
  58. data/lib/codebot/network_manager.rb +181 -0
  59. data/lib/codebot/options.rb +49 -0
  60. data/lib/codebot/options/base.rb +55 -0
  61. data/lib/codebot/options/core.rb +126 -0
  62. data/lib/codebot/options/integration.rb +101 -0
  63. data/lib/codebot/options/network.rb +109 -0
  64. data/lib/codebot/payload.rb +32 -0
  65. data/lib/codebot/request.rb +51 -0
  66. data/lib/codebot/sanitizers.rb +130 -0
  67. data/lib/codebot/serializable.rb +101 -0
  68. data/lib/codebot/shortener.rb +43 -0
  69. data/lib/codebot/thread_controller.rb +70 -0
  70. data/lib/codebot/user_error.rb +13 -0
  71. data/lib/codebot/validation_error.rb +17 -0
  72. data/lib/codebot/web_listener.rb +107 -0
  73. data/lib/codebot/web_server.rb +58 -0
  74. data/webhook.png +0 -0
  75. metadata +249 -0
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: false
2
+
3
+ module Codebot
4
+ module Formatters
5
+ module Gitlab
6
+ # This class formats Push events from Gitlab
7
+ class PushHook < Formatter
8
+ def before_commit
9
+ extract(:before)
10
+ end
11
+
12
+ def after_commit
13
+ extract(:after)
14
+ end
15
+
16
+ def repository_name
17
+ extract(:repository, :name)
18
+ end
19
+
20
+ def repository_url
21
+ extract(:repository, :homepage)
22
+ end
23
+
24
+ def compare_url
25
+ commits = "#{before_commit}...#{before_commit}"
26
+ shorten_url "#{repository_url}/compare/#{commits}"
27
+ end
28
+
29
+ def commit_default_format
30
+ '%<repository>s/%<branch>s %<hash>s %<author>s: %<title>s'
31
+ end
32
+
33
+ def commit_author(commit)
34
+ return nil unless commit['author'].is_a? Hash
35
+
36
+ commit['author']['name']
37
+ end
38
+
39
+ def commit_summary(commit)
40
+ commit_default_format % {
41
+ repository: format_repository(repository_name),
42
+ branch: format_branch(branch),
43
+ hash: format_hash(commit['id']),
44
+ author: format_user(commit_author(commit)),
45
+ title: prettify(commit['message'])
46
+ }
47
+ end
48
+
49
+ def branch
50
+ extract(:ref).split('/')[2..-1].join('/')
51
+ end
52
+
53
+ def num_commits
54
+ format_number(extract(:total_commits_count).to_i,
55
+ 'new commit', 'new commits')
56
+ end
57
+
58
+ def summary_format
59
+ '[%<repository>s] %<user>s pushed %<num_commits>s ' \
60
+ 'to %<branch>s: %<url>s'
61
+ end
62
+
63
+ def default_summary
64
+ user_name = extract(:user_name)
65
+
66
+ summary_format % {
67
+ repository: format_repository(repository_name),
68
+ user: format_user(user_name),
69
+ num_commits: num_commits,
70
+ branch: format_branch(branch),
71
+ url: compare_url
72
+ }
73
+ end
74
+
75
+ def format
76
+ [default_summary] + extract(:commits).map do |commit|
77
+ commit_summary(commit)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebot
4
+ module Formatters
5
+ module Gitlab
6
+ # Triggers on a Wiki Page Hook event
7
+ class WikiPageHook < Formatter
8
+ def format
9
+ ["#{summary}: #{format_url url}"]
10
+ end
11
+
12
+ def summary
13
+ default_format % {
14
+ repository: format_repository(repository_name),
15
+ sender: format_user(sender_name),
16
+ action: action,
17
+ title: wiki_title
18
+ }
19
+ end
20
+
21
+ def default_format
22
+ '[%<repository>s] %<sender>s %<action>s page \'%<title>s\''
23
+ end
24
+
25
+ def repository_name
26
+ extract(:project, :path_with_namespace)
27
+ end
28
+
29
+ def sender_name
30
+ extract(:user, :name)
31
+ end
32
+
33
+ def summary_url
34
+ extract(:object_attributes, :url)
35
+ end
36
+
37
+ def action
38
+ case wiki_action
39
+ when 'create' then 'created'
40
+ when 'delete' then 'deleted'
41
+ when 'update', nil then 'updated'
42
+ else wiki_action
43
+ end
44
+ end
45
+
46
+ def wiki_action
47
+ extract(:object_attributes, :action)
48
+ end
49
+
50
+ def wiki_title
51
+ extract(:object_attributes, :title)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Portions (c) 2008 Logical Awesome, LLC (released under the MIT license).
4
+ # See the LICENSE file for the full MIT license text.
5
+
6
+ module Codebot
7
+ module Formatters
8
+ # This class formats gollum events.
9
+ class Gollum < Formatter
10
+ # Formats IRC messages for a gollum event.
11
+ #
12
+ # @return [Array<String>] the formatted messages
13
+ def format
14
+ ["#{summary}: #{format_url url}"]
15
+ end
16
+
17
+ def summary
18
+ default_format % {
19
+ repository: format_repository(repository_name),
20
+ sender: format_user(sender_name),
21
+ summary: (pages.one? ? single_page_summary : multi_page_summary)
22
+ }
23
+ end
24
+
25
+ def default_format
26
+ '[%<repository>s] %<sender>s %<summary>s'
27
+ end
28
+
29
+ def single_page_summary
30
+ page = pages.first.to_h
31
+ short = prettify page['summary']
32
+ suffix = ": #{short}" unless short.empty?
33
+ "#{page['action']} wiki page #{page['title']}#{suffix}"
34
+ end
35
+
36
+ def multi_page_summary
37
+ actions = []
38
+ counts = action_counts
39
+ counts.each { |verb, num| actions << "#{verb} #{format_number num}" }
40
+ changes = ary_to_sentence(
41
+ actions,
42
+ 'pushed an empty commit that did not affect any'
43
+ )
44
+ singular_noun = counts.last.to_a.last.to_i.eql?(1)
45
+ "#{changes} wiki #{singular_noun ? 'page' : 'pages'}"
46
+ end
47
+
48
+ def action_counts
49
+ Hash.new(0).tap do |hash|
50
+ pages.each { |page| hash[page['action']] += 1 }
51
+ end.sort
52
+ end
53
+
54
+ def summary_url
55
+ if pages.one?
56
+ pages.first['html_url'].to_s
57
+ else
58
+ "#{repository_url}/wiki"
59
+ end
60
+ end
61
+
62
+ def pages
63
+ extract(:pages).to_a
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebot
4
+ module Formatters
5
+ # This class formats issue_comment events.
6
+ class IssueComment < Formatter
7
+ # Formats IRC messages for an issue_comment event.
8
+ #
9
+ # @return [Array<String>] the formatted messages
10
+ def format
11
+ ["#{summary}: #{format_url url}"]
12
+ end
13
+
14
+ def summary
15
+ default_format % {
16
+ repository: format_repository(repository_name),
17
+ sender: format_user(sender_name),
18
+ number: issue_number,
19
+ summary: prettify(comment_body)
20
+ }
21
+ end
22
+
23
+ def default_format
24
+ '[%<repository>s] %<sender>s commented on issue' \
25
+ ' #%<number>s: %<summary>s'
26
+ end
27
+
28
+ def summary_url
29
+ extract(:comment, :html_url).to_s
30
+ end
31
+
32
+ def comment_body
33
+ extract(:comment, :body).to_s
34
+ end
35
+
36
+ def issue_number
37
+ extract(:issue, :number)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebot
4
+ module Formatters
5
+ # This class formats issues events.
6
+ class Issues < Formatter
7
+ # Formats IRC messages for an issue event.
8
+ #
9
+ # @return [Array<String>] the formatted messages
10
+ def format
11
+ ["#{summary}: #{format_url url}"] if opened? || closed?
12
+ end
13
+
14
+ def summary
15
+ default_format % {
16
+ repository: format_repository(repository_name),
17
+ sender: format_user(sender_name),
18
+ action: action,
19
+ number: issue_number,
20
+ title: issue_title
21
+ }
22
+ end
23
+
24
+ def default_format
25
+ '[%<repository>s] %<sender>s %<action>s issue #%<number>s: %<title>s'
26
+ end
27
+
28
+ def summary_url
29
+ extract(:issue, :html_url).to_s
30
+ end
31
+
32
+ def issue_number
33
+ extract(:issue, :number)
34
+ end
35
+
36
+ def issue_title
37
+ extract(:issue, :title)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebot
4
+ module Formatters
5
+ # This class formats ping events.
6
+ class Ping < Formatter
7
+ # Formats IRC messages for a ping event.
8
+ #
9
+ # @return [Array<String>] the formatted messages
10
+ def format
11
+ ["#{summary}: #{format_url url}"]
12
+ end
13
+
14
+ def summary
15
+ default_format % {
16
+ scope: format_scope,
17
+ sender: format_user(sender_name),
18
+ events: format_events
19
+ }
20
+ end
21
+
22
+ def default_format
23
+ '[%<scope>s] %<sender>s added a webhook for %<events>s'
24
+ end
25
+
26
+ def summary_url
27
+ case extract(:hook, :type)
28
+ when /\Aorganization\z/i
29
+ login = extract(:organization, :login).to_s
30
+ "https://github.com/#{login}"
31
+ when /\Arepository\z/i
32
+ extract(:repository, :html_url).to_s
33
+ end
34
+ end
35
+
36
+ def format_events
37
+ if hook_events.empty?
38
+ 'no events'
39
+ elsif hook_events.include? '*'
40
+ format_event 'all events'
41
+ else
42
+ format_events_some
43
+ end
44
+ end
45
+
46
+ def format_events_some
47
+ if hook_events.length > 5
48
+ "#{format_number(hook_events.length)} events"
49
+ elsif hook_events.one?
50
+ "the #{format_event hook_events.first} event"
51
+ else
52
+ "the #{formatted_hook_events} events"
53
+ end
54
+ end
55
+
56
+ def hook_events
57
+ extract(:hook, :events).to_a.uniq
58
+ end
59
+
60
+ def formatted_hook_events
61
+ ary_to_sentence(hook_events.sort.map { |event| format_event event })
62
+ end
63
+
64
+ # Formats the name of the repository or organization the webhook belongs
65
+ # to.
66
+ #
67
+ # @return [String] the formatted scope
68
+ def format_scope
69
+ case extract(:hook, :type)
70
+ when /\Aorganization\z/i
71
+ format_user extract(:organization, :login)
72
+ when /\Arepository\z/i
73
+ login = extract(:repository, :owner, :login)
74
+ "#{format_user login}/#{format_repository repository_name}"
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebot
4
+ module Formatters
5
+ # This class formats public events.
6
+ class Public < Formatter
7
+ # Formats IRC messages for a public event.
8
+ #
9
+ # @return [Array<String>] the formatted messages
10
+ def format
11
+ ["#{summary}: #{format_url url}"]
12
+ end
13
+
14
+ def summary
15
+ default_format % {
16
+ repository: format_repository(repository_name),
17
+ sender: format_user(sender_name)
18
+ }
19
+ end
20
+
21
+ def default_format
22
+ '[%<repository>s] %<sender>s open-sourced the repository'
23
+ end
24
+
25
+ def summary_url
26
+ repository_url
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Portions (c) 2008 Logical Awesome, LLC (released under the MIT license).
4
+ # See the LICENSE file for the full MIT license text.
5
+
6
+ module Codebot
7
+ module Formatters
8
+ # This class formats pull_request events.
9
+ class PullRequest < Formatter
10
+ # Formats IRC messages for a pull_request event.
11
+ #
12
+ # @return [Array<String>] the formatted messages
13
+ def format
14
+ ["#{summary}: #{format_url url}"] if opened? || closed?
15
+ end
16
+
17
+ def summary
18
+ default_format % {
19
+ repository: format_repository(repository_name),
20
+ sender: format_user(sender_name),
21
+ action: action,
22
+ number: pull_number,
23
+ title: pull_title,
24
+ base_ref: pull_base_ref,
25
+ head_title: pull_head_title
26
+ }
27
+ end
28
+
29
+ def default_format
30
+ '[%<repository>s] %<sender>s %<action>s pull request #%<number>s: ' \
31
+ '%<title>s (%<base_ref>s...%<head_title>s)'
32
+ end
33
+
34
+ def pull_number
35
+ extract(:pull_request, :number)
36
+ end
37
+
38
+ def pull_title
39
+ extract(:pull_request, :title)
40
+ end
41
+
42
+ def pull_base_label
43
+ extract(:pull_request, :base, :label)
44
+ end
45
+
46
+ def pull_base_ref
47
+ pull_base_label.to_s.split(':').last
48
+ end
49
+
50
+ def pull_head_label
51
+ extract(:pull_request, :head, :label)
52
+ end
53
+
54
+ def pull_head_ref
55
+ pull_head_label.to_s.split(':').last
56
+ end
57
+
58
+ def pull_head_title
59
+ if pull_head_ref == pull_base_ref
60
+ pull_head_ref
61
+ else
62
+ pull_head_label
63
+ end
64
+ end
65
+
66
+ def summary_url
67
+ extract(:pull_request, :html_url).to_s
68
+ end
69
+ end
70
+ end
71
+ end