solicit 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 115b96f84a7bc69ebfabf45139d2261663e73f2b0895d0ce8456a055c124f7af
4
+ data.tar.gz: 736dca15502cdfad1c6218d083a0567938e11cf4bdc29d02c79c413b790f5625
5
+ SHA512:
6
+ metadata.gz: 0ddb5c194e2a18cb5f05b7f26817decfe1bb9f47d6d88683df6166c866e9beab6ed1919761324c41f0b63de50224bcd27c3c722d81a2346e3890484e3c208a63
7
+ data.tar.gz: 9f07848217775d9de5713802b436e3f310a3f32348f2469645a4438c6d415bc1e20539868105b70ac8ad748f063e87b8aae81570736a3452ee8aba8bcbb7bd04
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Solicit
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/solicit`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'solicit'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install solicit
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/solicit.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,68 @@
1
+ module Solicit
2
+ class PullRequestsController < ActionController::Base
3
+ before_action :ensure_can_claim, only: :claim
4
+ before_action :ensure_can_notify, only: :notify
5
+
6
+ def claim
7
+ render json: ClaimPullRequest.perform(
8
+ url: payload[:callback_id],
9
+ label: payload.dig(:actions, 0, :value),
10
+ assignee: Solicit.contributors_map[payload.dig(:user, :name)],
11
+ original: payload[:original_message]
12
+ )
13
+ end
14
+
15
+ def notify
16
+ PostToSlack.perform(
17
+ url: Solicit.slack_webhook_url,
18
+ channel: Solicit.labels_map[payload.dig(:label, :name).to_sym],
19
+ username: Solicit.slack_username,
20
+ payload: payload
21
+ )
22
+ head :ok
23
+ end
24
+
25
+ private
26
+
27
+ def ensure_can_claim
28
+ head :ok unless request_is_from_slack? &&
29
+ payload.dig(:user, :name) &&
30
+ Solicit.contributors_map.key?(payload.dig(:user, :name)) &&
31
+ payload[:callback_id] &&
32
+ payload[:original_message] &&
33
+ payload.dig(:actions, 0, :value)
34
+ end
35
+
36
+ def ensure_can_notify
37
+ head :ok unless request_is_from_github? &&
38
+ payload[:action] == 'labeled' &&
39
+ Solicit.labels_map.key?(payload.dig(:label, :name).to_sym) &&
40
+ payload.dig(:pull_request, :number) &&
41
+ payload.dig(:repository, :url)
42
+ end
43
+
44
+ def request_is_from_slack?
45
+ return true unless Solicit.slack_secret
46
+ signature = 'v0=' + OpenSSL::HMAC.hexdigest(
47
+ OpenSSL::Digest::SHA256.new,
48
+ Solicit.slack_secret,
49
+ ['v0', request.headers['X-Slack-Request-Timestamp'], request.body.read].join(':')
50
+ )
51
+ Rack::Utils.secure_compare(signature, request.headers['X-Slack-Signature'])
52
+ end
53
+
54
+ def request_is_from_github?
55
+ return true unless Solicit.github_secret
56
+ signature = 'sha1=' + OpenSSL::HMAC.hexdigest(
57
+ OpenSSL::Digest.new('sha1'),
58
+ Solicit.github_secret,
59
+ request.body.read
60
+ )
61
+ Rack::Utils.secure_compare(signature, request.headers['HTTP_X_HUB_SIGNATURE'])
62
+ end
63
+
64
+ def payload
65
+ @payload ||= JSON.parse(params.require(:payload)).with_indifferent_access
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,45 @@
1
+ module Solicit
2
+ class ClaimPullRequest
3
+
4
+ def initialize(url:, label:, assignee:, original:)
5
+ @url = url
6
+ @label = label
7
+ @assignee = assignee
8
+ @original = original
9
+ end
10
+
11
+ def self.perform(*args)
12
+ new(*args).perform
13
+ end
14
+
15
+ def perform
16
+ return unless claim_pull_request.success?
17
+
18
+ @original[:attachments].reject! { |a| a[:callback_id] == @url } unless needs_more_assignees?
19
+ @original[:attachments] << { color: :good, text: claim_message }
20
+ @original
21
+ end
22
+
23
+ private
24
+
25
+ def claim_pull_request
26
+ return unless @assignee['handle'].presence
27
+ HTTParty.post @url, default_github_params.merge(body: { assignees: Array(@assignee['handle']) }.to_json)
28
+ end
29
+
30
+ def needs_more_assignees?
31
+ response = HTTParty.get @url.gsub('/assignees', ''), default_github_params
32
+ Solicit.needs_more_assignees.call(response, @label)
33
+ end
34
+
35
+ def claim_message
36
+ I18n.t :"engines.solicit.volunteer",
37
+ name: @assignee.fetch('name', 'Someone'),
38
+ emoji: @assignee.fetch('emoji', 'star2')
39
+ end
40
+
41
+ def default_github_params
42
+ { query: { access_token: Solicit.github_api_token } }
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,41 @@
1
+ module Solicit
2
+ class PostToSlack
3
+
4
+ def initialize(url:, channel:, username:, payload:)
5
+ @url = url
6
+ @channel = channel
7
+ @username = username
8
+ @payload = payload
9
+ end
10
+
11
+ def self.perform(*args)
12
+ new(*args).perform
13
+ end
14
+
15
+ def perform
16
+ Slack::Notifier.new(@url, channel: @channel, username: @username).ping(
17
+ text: I18n.t(:"engines.solicit.title",
18
+ link: @payload.dig(:pull_request, :html_url),
19
+ title: @payload.dig(:pull_request, :title),
20
+ label: @payload.dig(:label, :name)
21
+ ),
22
+ attachments: [{
23
+ title: I18n.t(:"engines.solicit.review"),
24
+ callback_id: [
25
+ @payload.dig(:repository, :url),
26
+ 'issues',
27
+ @payload.dig(:pull_request, :number),
28
+ 'assignees',
29
+ ].join('/'),
30
+ color: :warning,
31
+ actions: [{
32
+ name: :claim,
33
+ text: I18n.t(:"engines.solicit.claim"),
34
+ type: :button,
35
+ value: @payload.dig(:label, :name),
36
+ }],
37
+ }]
38
+ )
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,7 @@
1
+ en:
2
+ engines:
3
+ solicit:
4
+ volunteer: "%{name} has volunteered! :%{emoji}:"
5
+ claim: "I'll do it!"
6
+ review: "Review this PR"
7
+ title: "PR <%{link}|%{title}> now has a %{label} label!"
data/config/routes.rb ADDED
@@ -0,0 +1,6 @@
1
+ Solicit::Engine.routes.draw do
2
+ resources :pull_requests, only: [] do
3
+ post :claim, on: :collection
4
+ post :notify, on: :collection
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module Solicit
2
+ VERSION = "0.1.0"
3
+ end
data/lib/solicit.rb ADDED
@@ -0,0 +1,26 @@
1
+ require "solicit/version"
2
+
3
+ module Solicit
4
+ class << self
5
+ mattr_accessor :labels_map,
6
+ :contributors_map,
7
+ :slack_webhook_url,
8
+ :slack_username,
9
+ :slack_secret,
10
+ :github_api_token,
11
+ :github_secret,
12
+ :needs_more_assignees
13
+
14
+ # by default, always remove the "I'll do it" button;
15
+ # the main app can define more complicated behaviour here if necessary
16
+ self.needs_more_assignees = Proc.new { false }
17
+ end
18
+
19
+ class Engine < ::Rails::Engine
20
+ isolate_namespace Solicit
21
+
22
+ config.before_initialize do
23
+ config.i18n.load_path += Dir["#{config.root}/config/locales/**/*.yml"]
24
+ end
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: solicit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Optimal Workshop
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-04-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.1.6
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 5.1.6.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 5.1.6
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 5.1.6.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: httparty
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.16'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.16'
47
+ - !ruby/object:Gem::Dependency
48
+ name: json
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.2'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.2'
61
+ - !ruby/object:Gem::Dependency
62
+ name: slack-notifier
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '2.3'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '2.3'
75
+ - !ruby/object:Gem::Dependency
76
+ name: sqlite3
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ description: ''
90
+ email:
91
+ executables: []
92
+ extensions: []
93
+ extra_rdoc_files: []
94
+ files:
95
+ - README.md
96
+ - Rakefile
97
+ - app/controllers/solicit/pull_requests_controller.rb
98
+ - app/use_cases/solicit/claim_pull_request.rb
99
+ - app/use_cases/solicit/post_to_slack.rb
100
+ - config/locales/en.yml
101
+ - config/routes.rb
102
+ - lib/solicit.rb
103
+ - lib/solicit/version.rb
104
+ homepage:
105
+ licenses:
106
+ - MIT
107
+ metadata: {}
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 2.7.8
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: Solicit reviewers for your github pull requests on Slack
128
+ test_files: []