issue 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29925e2f5c0b58136fe7097671b9577766034701c97aeb78fc9999a8fb4e23ee
4
- data.tar.gz: 54d441c401a125e0e0ebea5baa48ead70dc3dcd5ad4a49c660673a4c626e3e07
3
+ metadata.gz: 10960451c8f6e5f752cc0a2b892ae8b8d122a14e1aaedc3671daa2da41cb80b8
4
+ data.tar.gz: b84a85ae117417a348dacfde4b387128190dcb72232e69abb96805eed8585926
5
5
  SHA512:
6
- metadata.gz: 495c6477690e7bc7c688876ac242bb7884f87c9746dcc3ba6e0e2b8cbd8a012a758afcf07a2ef9f09b1a9280afac97a255a317fdcbfabb4668860a442dd04f37
7
- data.tar.gz: 688bb57f456b5831a0840d8ad847bcd24a11baf42e43c09b1fe66fd2ae5292088da86aef45075c3c5025e39e792f51dff5d73594f7fea7f9a1d4605a2c05a0f2
6
+ metadata.gz: 60caa264fa776efee538761cfa9d06794859bca2490247e9cfdc76e1ea2c86a6e78b6e19fead11f98f522607c26224114b7db564404dd39657c35043f605ef87
7
+ data.tar.gz: 501ac0d34f7c80334a66ce90574b2677750b1b23287d2bb65682783fd21413504dec767e6decba5307ac8ddcf0c20beaa5df188f1e23d097ae2849baa66f2da0
data/lib/issue.rb CHANGED
@@ -1,5 +1,6 @@
1
- require 'issue/version'
2
-
3
1
  module Issue
4
-
2
+ require_relative "issue/version"
3
+ require_relative "issue/payload"
4
+ require_relative "issue/webhook"
5
+ require_relative "issue/error"
5
6
  end
@@ -0,0 +1,15 @@
1
+ module Issue
2
+ class Error
3
+ attr :status
4
+ attr :message
5
+
6
+ # Initialize Issue::Error object with:
7
+ # status: html status code
8
+ # msg: message to send back in response
9
+ def initialize(status, msg)
10
+ @status = status
11
+ @message = msg
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,112 @@
1
+ require "ostruct"
2
+ require "json"
3
+
4
+ module Issue
5
+ class Payload
6
+ attr_accessor :context
7
+
8
+ # Initialize Issue::Payload object with:
9
+ # json_data: the json sent from a GitHub webhook
10
+ # event: the value of the HTTP_X_GITHUB_EVENT header
11
+ #
12
+ # Initializing a new Issue::Payload instance makes all this info
13
+ # from the json webhook available via accessor methods:
14
+ #
15
+ # action
16
+ # event
17
+ # issue_id
18
+ # issue_title
19
+ # issue_body
20
+ # issue_author
21
+ # repo
22
+ # sender
23
+ # event_action
24
+ # raw_payload
25
+ #
26
+ # And if the case the event is 'issue_comment' also:
27
+ #
28
+ # comment_body
29
+ # comment_created_at
30
+ # comment_url
31
+ #
32
+ def initialize(json_data, event)
33
+ action = json_data.dig("action")
34
+ sender = json_data.dig("sender", "login")
35
+ issue_id = json_data.dig("issue", "number")
36
+ issue_title = json_data.dig("issue", "title")
37
+ issue_body = json_data.dig("issue", "body")
38
+ issue_labels = json_data.dig("issue", "labels")
39
+ issue_author = json_data.dig("issue", "user", "login")
40
+ repo = json_data.dig("repository", "full_name")
41
+
42
+ @context = OpenStruct.new(
43
+ action: action,
44
+ event: event,
45
+ issue_id: issue_id,
46
+ issue_title: issue_title,
47
+ issue_body: issue_body,
48
+ issue_author: issue_author,
49
+ issue_labels: issue_labels,
50
+ repo: repo,
51
+ sender: sender,
52
+ event_action: "#{event}.#{action}",
53
+ raw_payload: json_data
54
+ )
55
+
56
+ if event == "issue_comment"
57
+ @context[:comment_body] = json_data.dig("comment", "body")
58
+ @context[:comment_created_at] = json_data.dig("comment", "created_at")
59
+ @context[:comment_url] = json_data.dig("comment", "html_url")
60
+ end
61
+
62
+ @context.each_pair do |method_name, value|
63
+ define_singleton_method(method_name) {value}
64
+ end
65
+ end
66
+
67
+ # True if the payload is coming from an issue that has just been opened
68
+ def opened?
69
+ action == "opened" || action == "reopened"
70
+ end
71
+
72
+ # True if the payload is coming from an issue that has just been closed
73
+ def closed?
74
+ action == "closed"
75
+ end
76
+
77
+ # True if the payload is coming from a new comment
78
+ def commented?
79
+ action == "created"
80
+ end
81
+
82
+ # True if the payload is coming from an edition of a comment or issue
83
+ def edited?
84
+ action == "edited"
85
+ end
86
+
87
+ # True if the payload is coming from locking an issue
88
+ def locked?
89
+ action == "locked"
90
+ end
91
+
92
+ # True if the payload is coming from unlocking an issue
93
+ def unlocked?
94
+ action == "unlocked"
95
+ end
96
+
97
+ # True if the payload is coming from pinning or unpinning an issue
98
+ def pinned?
99
+ action == "pinned" || action == "unpinned"
100
+ end
101
+
102
+ # True if the payload is coming from un/assigning an issue
103
+ def assigned?
104
+ action == "assigned" || action == "unassigned"
105
+ end
106
+
107
+ # True if the payload is coming from un/labeling an issue
108
+ def labeled?
109
+ action == "labeled" || action == "unlabeled"
110
+ end
111
+ end
112
+ end
data/lib/issue/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Issue
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,92 @@
1
+ require "ostruct"
2
+ require "json"
3
+ require "openssl"
4
+ require "rack"
5
+
6
+ module Issue
7
+ class Webhook
8
+ attr_accessor :secret_token
9
+ attr_accessor :request
10
+ attr_accessor :accept_origin
11
+ attr_accessor :discard_sender
12
+ attr_accessor :accept_events
13
+ attr_accessor :error
14
+ attr_accessor :payload
15
+
16
+ # Initialize the Issue::Webhook object
17
+ # This method should receive a Hash with the following settings:
18
+ # * secret_token: the GitHub secret token needed to verify the request signature
19
+ # * accept_events: an Array of valid values for the HTTP_X_GITHUB_EVENT header. If empty any event will be precessed.
20
+ # * origin: the respository where the webhook should be sent to be accepted. If empty any request will be precessed.
21
+ # * discard_sender: an optional GitHub user handle to discard all events triggered by it.
22
+ def initialize(settings={})
23
+ @secret_token = settings[:secret_token]
24
+ @accept_origin = settings[:origin]
25
+ @discard_sender = settings[:discard_sender]
26
+ @accept_events = [settings[:accept_events]].flatten.compact.uniq.map(&:to_s)
27
+ end
28
+
29
+ # This method will parse the passed request.
30
+ # If the request signature is incorrect or any of the conditions set
31
+ # via the initialization settings are not met an error will be created
32
+ # with the appropiate html status and message. Otherwise a Issue::Payload
33
+ # object will be created with the information contained in the request payload.
34
+ #
35
+ # This method returns a pair [payload, error] where only one of them will be nil
36
+ def parse_request(request)
37
+ @payload = nil
38
+ @error = nil
39
+ @request = request
40
+
41
+ if verify_signature
42
+ parse_payload
43
+ end
44
+
45
+ return [payload, error]
46
+ end
47
+
48
+ # This method returns True if parsing a request has generated an Issue::Error object
49
+ # That object will be available at the #error accessor method.
50
+ def errored?
51
+ !error.nil?
52
+ end
53
+
54
+ private
55
+
56
+ def verify_signature
57
+ gh_signature = request.get_header "HTTP_X_HUB_SIGNATURE"
58
+ return error!(500, "Can't compute signature") if secret_token.nil? || secret_token.empty?
59
+ return error!(403, "Request missing signature") if gh_signature.nil? || gh_signature.empty?
60
+ request.body.rewind
61
+ payload_body = request.body.read
62
+ signature = "sha1=" + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha1"), secret_token, payload_body)
63
+ return error!(403, "Signatures didn't match!") unless Rack::Utils.secure_compare(signature, gh_signature)
64
+ true
65
+ end
66
+
67
+ def parse_payload
68
+ begin
69
+ request.body.rewind
70
+ json_payload = JSON.parse(request.body.read)
71
+ event = request.get_header "HTTP_X_GITHUB_EVENT"
72
+ sender = json_payload.dig("sender", "login")
73
+ origin = json_payload.dig("repository", "full_name")
74
+ rescue JSON::ParserError
75
+ return error!(400, "Malformed request")
76
+ end
77
+
78
+ return error!(422, "No payload") if json_payload.nil? || json_payload.empty?
79
+ return error!(422, "No event") if event.nil?
80
+ return error!(200, "Event discarded") unless (accept_events.empty? || accept_events.include?(event))
81
+ return error!(200, "Event origin discarded") if (discard_sender && sender == discard_sender)
82
+ return error!(403, "Event origin not allowed") if (accept_origin && origin != accept_origin)
83
+
84
+ @payload = Issue::Payload.new(json_payload, event)
85
+ end
86
+
87
+ def error!(status, msg)
88
+ @error = Issue::Error.new(status, msg)
89
+ false
90
+ end
91
+ end
92
+ end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: issue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juanjo Bazán
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-29 00:00:00.000000000 Z
11
+ date: 2021-07-01 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: openssl
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: rake
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -47,14 +75,17 @@ extra_rdoc_files: []
47
75
  files:
48
76
  - README.md
49
77
  - lib/issue.rb
78
+ - lib/issue/error.rb
79
+ - lib/issue/payload.rb
50
80
  - lib/issue/version.rb
81
+ - lib/issue/webhook.rb
51
82
  homepage: http://github.com/xuanxu/issue
52
83
  licenses:
53
84
  - MIT
54
85
  metadata:
55
86
  bug_tracker_uri: https://github.com/xuanxu/issue/issues
56
87
  changelog_uri: https://github.com/xuanxu/issue/blob/master/CHANGELOG.md
57
- documentation_uri: https://www.rubydoc.info/gems/emoticon
88
+ documentation_uri: https://www.rubydoc.info/gems/issue
58
89
  homepage_uri: http://github.com/xuanxu/issue
59
90
  source_code_uri: http://github.com/xuanxu/issue
60
91
  post_install_message: