loadrunner 0.0.4 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b8a007f7920f1973efc60d3795c4cd8dab52cb3d
4
- data.tar.gz: 0baaf60bb349d17969597985c564bdb68daf1391
3
+ metadata.gz: 45e2aa0edf131bb75fdac7ac306131ba87791958
4
+ data.tar.gz: b6380a094f0d73e15e3922b3b2caea0e90db56b6
5
5
  SHA512:
6
- metadata.gz: dd2ddfff2c1dfa0522871c2a41c84e60b36934e56d5785e52172d5cc4bccb17c99cde8e58d78b580a4181448ba252b9b99a512ee803e694e390598f38536ef23
7
- data.tar.gz: 714bea8499b8c53e358dfca0fe09e75cd97455b97729f49bd99f71d15f6e91b51562c60b0c31386ebdb5cd954325eaa2336a5b91de7bce28f8a820dabee645f1
6
+ metadata.gz: a8775a42b092fb08485fdf72525ed2dcaa48f59f908f593c4ba8859a22739abdb671b0d3edfc92f3cc086198d875cccc5bc8322190f2202998846182506667be
7
+ data.tar.gz: 3fe722e065dab62c742d337c006b2cd2ccea46920cd2a70692a645250d721d609b47574e5af23c1d0d50d040df22cb5afa64e3c760384eb04e397430a4ed65c5
data/README.md CHANGED
@@ -8,13 +8,16 @@ LoadRunner - GitHub Webhook Server and Event Simulator
8
8
 
9
9
  ---
10
10
 
11
- LoadRunner is a dual-purpose utility for working with GitHub webhooks.
11
+ LoadRunner is a multi-purpose utility for working with GitHub webhooks and
12
+ statuses.
12
13
 
13
14
  It provides these features:
14
15
 
15
16
  - A webserver that responds to GitHub webhook events and can run any
16
17
  arbitrary script writtn in any language.
17
- - A command line utility for testing your webhook server configuration.
18
+ - A command line utility for testing your webhook server configuration by
19
+ sending simulated events.
20
+ - A command line utility for sending status updates to pull requests.
18
21
 
19
22
  ---
20
23
 
@@ -43,3 +46,9 @@ Getting Started
43
46
  $ cat output.txt
44
47
 
45
48
 
49
+ For more options, see the [documentation][1] or run
50
+
51
+ $ loadrunner --help
52
+
53
+
54
+ [1]: http://www.rubydoc.info/gems/loadrunner
@@ -1,6 +1,8 @@
1
1
  require 'httparty'
2
2
 
3
3
  module LoadRunner
4
+
5
+ # Send simulated GitHub events to any webhook server
4
6
  class Client
5
7
  include HTTParty
6
8
  attr_accessor :secret_token, :base_url, :payload
@@ -11,11 +13,18 @@ module LoadRunner
11
13
  self.class.base_uri base_url
12
14
  end
13
15
 
16
+ # Send a simulated event using a shorthand syntax. opts can contain
17
+ # any of these:
18
+ # * +repo+: repository name
19
+ # * +ref+: ref ID (for example +ref/heads/branchname+)
20
+ # * +branch+: branch name
21
+ # * +tag+: tag name
14
22
  def send(event=:push, opts={})
15
23
  payload = build_payload opts
16
24
  send_payload event, payload
17
25
  end
18
26
 
27
+ # Send a simulated event. Payload can be a hash or a JSON string.
19
28
  def send_payload(event, payload)
20
29
  @payload = payload.is_a?(String) ? payload : payload.to_json
21
30
  headers = headers event
@@ -1,12 +1,13 @@
1
1
  require 'singleton'
2
2
  require 'docopt'
3
- require 'awesome_print'
3
+ require 'colsole'
4
4
 
5
5
  module LoadRunner
6
6
 
7
7
  # Handles the command line interface
8
8
  class CommandLine
9
9
  include Singleton
10
+ include Colsole
10
11
 
11
12
  attr_reader :args
12
13
 
@@ -28,15 +29,14 @@ module LoadRunner
28
29
  # delegate action to other, more specialized methods.
29
30
  def handle
30
31
  return send if args['send']
32
+ return status if args['status']
31
33
  return server if args['server']
32
34
  end
33
35
 
34
36
  def send
35
37
  client = Client.new client_opts
36
38
  response = client.send args['EVENT'], payload_opts
37
-
38
- puts "Reesponse code: #{response.code}" if response.respond_to? :code
39
- ap response
39
+ show response
40
40
  end
41
41
 
42
42
  def server
@@ -44,6 +44,20 @@ module LoadRunner
44
44
  Server.run!
45
45
  end
46
46
 
47
+ def status
48
+ api = GitHubAPI.new
49
+ opts = {
50
+ state: args['STATE'],
51
+ target_url: args['--url'],
52
+ context: args['--context'],
53
+ description: args['--desc']
54
+ }
55
+
56
+ response = api.status args['REPO'], args['SHA'], opts
57
+
58
+ show response
59
+ end
60
+
47
61
  def client_opts
48
62
  {
49
63
  base_url: args['URL'],
@@ -65,5 +79,16 @@ module LoadRunner
65
79
  result[:ref] = ref
66
80
  result
67
81
  end
82
+
83
+ # Print the response json to stdout, and the response code to stderr.
84
+ def show(response)
85
+ puts JSON.pretty_generate response
86
+
87
+ if response.respond_to? :code
88
+ code = response.code.to_s
89
+ color = code =~ /^2\d\d/ ? :txtgrn : :txtred
90
+ say! "!#{color}!Response Code: #{code}"
91
+ end
92
+ end
68
93
  end
69
94
  end
@@ -3,6 +3,7 @@ LoadRunner
3
3
  Usage:
4
4
  loadrunner server [--port N --bind IP]
5
5
  loadrunner send URL REPO EVENT [REF]
6
+ loadrunner status REPO SHA STATE [--context TEXT --desc TEXT --url URL]
6
7
  loadrunner (-h|--help|--version)
7
8
 
8
9
  Commands:
@@ -12,6 +13,9 @@ Commands:
12
13
  send
13
14
  Send a simulated GitHub event to a webhook server.
14
15
 
16
+ status
17
+ Send status update to a github pull request.
18
+
15
19
  Parameters:
16
20
  URL
17
21
  The URL of the webhook server. This server should have a /payload
@@ -31,6 +35,12 @@ Parameters:
31
35
  * branch=branch_name
32
36
  * raw ref string (for example refs/tags/tagname)
33
37
 
38
+ SHA
39
+ Commit SHA string.
40
+
41
+ STATE
42
+ One of 'success', 'pending', 'error', 'failure'
43
+
34
44
  Options:
35
45
  --port N
36
46
  Set the port of the webhook server.
@@ -38,6 +48,14 @@ Options:
38
48
  --bind IP
39
49
  Set the listening address of the webhook server.
40
50
 
51
+ --context TEXT
52
+ Indicate what service is sending this status.
53
+
54
+ --url URL
55
+ The target URL to associate with this status.
56
+
57
+ --desc TEXT
58
+ A short description of the status.
41
59
 
42
60
  Environment Variables:
43
61
  GITHUB_SECRET_TOKEN=y0urAP1k3y
@@ -54,4 +72,8 @@ Examples:
54
72
  loadrunner server
55
73
  loadrunner server --bind 0.0.0.0 --port 3000
56
74
 
75
+ # Send a status
76
+ loadrunner status me/myrepo 018b0ac... pending
77
+ loadrunner status me/myrepo 018b0ac... success --context "My CI"
78
+
57
79
 
@@ -0,0 +1,48 @@
1
+ require 'httparty'
2
+
3
+ module LoadRunner
4
+ # Communicate with GitHub
5
+ class GitHubAPI
6
+ include HTTParty
7
+
8
+ base_uri 'https://api.github.com'
9
+
10
+ # Send status update to a pull request. Supported options:
11
+ # * +state+: :pending, :success, :failure or :error
12
+ # * +context+: any string
13
+ # * +description+: any string
14
+ # * +target_url+: any valid URL
15
+ def status(repo, sha, opts={})
16
+ # sha = '018b0ac55dbf0d8e1eef6df46e04dfef8bea9b96'
17
+ message = {
18
+ body: {
19
+ state: (opts[:state] ? opts[:state].to_s : 'pending'),
20
+ context: (opts[:context] || 'LoadRunner'),
21
+ description: opts[:description],
22
+ target_url: opts[:target_url]
23
+ }.to_json
24
+ }
25
+ self.class.post "/repos/#{repo}/statuses/#{sha}", message.merge(request_options)
26
+ end
27
+
28
+ private
29
+
30
+ def request_options
31
+ {
32
+ headers: headers
33
+ }
34
+ end
35
+
36
+ def headers
37
+ {
38
+ "Authorization" => "token #{secret_token}",
39
+ "User-Agent" => "LoadRunner"
40
+ }
41
+ end
42
+
43
+ def secret_token
44
+ ENV['GITHUB_ACCESS_TOKEN']
45
+ end
46
+
47
+ end
48
+ end
@@ -1,5 +1,6 @@
1
1
  module LoadRunner
2
2
 
3
+ # Executes event handlers
3
4
  class Runner
4
5
  attr_reader :opts
5
6
  attr_accessor :response
@@ -8,6 +9,8 @@ module LoadRunner
8
9
  @opts = opts
9
10
  end
10
11
 
12
+ # Execute all matching handlers based on the input payload. This method
13
+ # populates the `#response` object, and returns true on success.
11
14
  def execute
12
15
  set_environment_vars
13
16
 
@@ -35,6 +38,7 @@ module LoadRunner
35
38
 
36
39
  private
37
40
 
41
+ # Find all handlers that fit the payload meta data.
38
42
  def locate_handlers
39
43
  handlers = []
40
44
 
@@ -45,17 +49,21 @@ module LoadRunner
45
49
  handlers
46
50
  end
47
51
 
52
+ # Execute all handlers.
48
53
  def execute_all(handlers)
49
54
  handlers.each do |handler|
50
55
  run_bg handler
51
56
  end
52
57
  end
53
58
 
59
+ # Run a command in the background.
54
60
  def run_bg(cmd)
55
61
  job = fork { exec cmd }
56
62
  Process.detach job
57
63
  end
58
64
 
65
+ # Set all payload meta data as environment variables so that the
66
+ # handler can use them.
59
67
  def set_environment_vars
60
68
  opts.each { |key, value| ENV[key.to_s.upcase] = value }
61
69
  end
@@ -3,6 +3,7 @@ module LoadRunner
3
3
  # The Sinatra server
4
4
  class Server < ServerBase
5
5
  include ServerHelper
6
+ include SignatureHelper
6
7
 
7
8
  get '/' do
8
9
  "OK"
@@ -1,23 +1,5 @@
1
1
  module LoadRunner
2
2
  module ServerHelper
3
- def verify_signature(payload_body, signature)
4
- return :no_client if secret_token and !signature
5
- return :no_server if !secret_token and signature
6
- return :ok if !secret_token and !signature
7
-
8
- expected_signature = generate_signature payload_body
9
- signature_match = Rack::Utils.secure_compare(expected_signature, signature)
10
- return signature_match ? :ok : :mismatch
11
- end
12
-
13
- def generate_signature(payload_body)
14
- 'sha1=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), secret_token, payload_body)
15
- end
16
-
17
- def secret_token
18
- ENV['GITHUB_SECRET_TOKEN']
19
- end
20
-
21
3
  def halt_messages
22
4
  {
23
5
  no_client: "Client did not send a signature",
@@ -0,0 +1,21 @@
1
+ module LoadRunner
2
+ module SignatureHelper
3
+ def verify_signature(payload_body, signature)
4
+ return :no_client if secret_token and !signature
5
+ return :no_server if !secret_token and signature
6
+ return :ok if !secret_token and !signature
7
+
8
+ expected_signature = generate_signature payload_body
9
+ signature_match = Rack::Utils.secure_compare(expected_signature, signature)
10
+ return signature_match ? :ok : :mismatch
11
+ end
12
+
13
+ def generate_signature(payload_body)
14
+ 'sha1=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), secret_token, payload_body)
15
+ end
16
+
17
+ def secret_token
18
+ ENV['GITHUB_SECRET_TOKEN']
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module LoadRunner
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/loadrunner.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  require 'load_runner/version'
2
- require 'load_runner/exceptions'
3
2
 
4
- require 'load_runner/runner'
3
+ require 'load_runner/signature_helper'
5
4
  require 'load_runner/server_helper'
5
+ require 'load_runner/git_hub_api'
6
+
7
+ require 'load_runner/runner'
6
8
  require 'load_runner/server_base'
7
9
  require 'load_runner/server'
8
10
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loadrunner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-16 00:00:00.000000000 Z
11
+ date: 2017-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -67,19 +67,19 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '5.1'
69
69
  - !ruby/object:Gem::Dependency
70
- name: awesome_print
70
+ name: colsole
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '1.8'
75
+ version: '0.5'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '1.8'
82
+ version: '0.5'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: runfile
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +178,20 @@ dependencies:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0.7'
181
+ - !ruby/object:Gem::Dependency
182
+ name: yard
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '0.9'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '0.9'
181
195
  description: Run your GitHub webhook server and Send simulated github events
182
196
  email: db@dannyben.com
183
197
  executables:
@@ -187,15 +201,15 @@ extra_rdoc_files: []
187
201
  files:
188
202
  - README.md
189
203
  - bin/loadrunner
190
- - lib/load_runner/_server.rb
191
204
  - lib/load_runner/client.rb
192
205
  - lib/load_runner/command_line.rb
193
206
  - lib/load_runner/docopt.txt
194
- - lib/load_runner/exceptions.rb
207
+ - lib/load_runner/git_hub_api.rb
195
208
  - lib/load_runner/runner.rb
196
209
  - lib/load_runner/server.rb
197
210
  - lib/load_runner/server_base.rb
198
211
  - lib/load_runner/server_helper.rb
212
+ - lib/load_runner/signature_helper.rb
199
213
  - lib/load_runner/version.rb
200
214
  - lib/loadrunner.rb
201
215
  homepage: https://github.com/DannyBen/loadrunner
@@ -1,44 +0,0 @@
1
- require 'sinatra'
2
- require "sinatra/reloader" if development?
3
- require 'json'
4
- require 'active_support/core_ext/hash/indifferent_access'
5
- require 'byebug'
6
-
7
- set port: 3000
8
- set bind: '0.0.0.0'
9
-
10
- ENV['SECRET_TOKEN'] = '123'
11
-
12
- post '/payload' do
13
- request.env['HTTP_X_HUB_SIGNATURE']
14
-
15
- request.body.rewind
16
- payload_body = request.body.read
17
-
18
- verify_signature payload_body
19
-
20
- push = ActiveSupport::HashWithIndifferentAccess.new JSON.parse payload_body
21
-
22
- branch = push[:ref] =~ /refs\/head/ ? push[:ref].sub('refs/heads/', '') : nil;
23
- tag = push[:ref] =~ /refs\/tags/ ? push[:ref].sub('refs/tags/', '') : nil;
24
-
25
- result = {
26
- event: request.env['HTTP_X_GITHUB_EVENT'],
27
- repo: push[:repository][:name],
28
- branch: branch,
29
- tag: tag
30
- # payload: push
31
- }
32
-
33
- result.inspect
34
- end
35
-
36
- post '/debug' do
37
- request.env['HTTP_X_HUB_SIGNATURE']
38
- end
39
-
40
- def verify_signature(payload_body)
41
- signature = 'sha1=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), ENV['SECRET_TOKEN'], payload_body)
42
- signature_match = Rack::Utils.secure_compare(signature, request.env['HTTP_X_HUB_SIGNATURE'])
43
- return halt 401, "Bad Signature" unless signature_match
44
- end
@@ -1,3 +0,0 @@
1
- module LoadRunner
2
- class Error < StandardError; end
3
- end