omg_pull_request 0.0.6

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 (42) hide show
  1. data/.gitignore +47 -0
  2. data/Gemfile +9 -0
  3. data/Gemfile.lock +68 -0
  4. data/LICENSE +22 -0
  5. data/README.md +66 -0
  6. data/Rakefile +12 -0
  7. data/bin/omg_pull_request +13 -0
  8. data/lib/omg_pull_request.rb +32 -0
  9. data/lib/omg_pull_request/aws/store.rb +30 -0
  10. data/lib/omg_pull_request/configuration.rb +55 -0
  11. data/lib/omg_pull_request/context.rb +29 -0
  12. data/lib/omg_pull_request/git_client.rb +31 -0
  13. data/lib/omg_pull_request/github_wrapper.rb +50 -0
  14. data/lib/omg_pull_request/lolcommits.rb +39 -0
  15. data/lib/omg_pull_request/notifications.rb +66 -0
  16. data/lib/omg_pull_request/prowl.rb +77 -0
  17. data/lib/omg_pull_request/test_logger.rb +20 -0
  18. data/lib/omg_pull_request/test_runner.rb +22 -0
  19. data/lib/omg_pull_request/test_runner/base.rb +128 -0
  20. data/lib/omg_pull_request/test_runner/rails.rb +19 -0
  21. data/lib/omg_pull_request/test_runner/ruby.rb +9 -0
  22. data/lib/omg_pull_request/version.rb +3 -0
  23. data/locales/en.yml +23 -0
  24. data/locales/omg.yml +20 -0
  25. data/omg_pull_request.gemspec +26 -0
  26. data/test/fixtures/comments +431 -0
  27. data/test/fixtures/config.yml +20 -0
  28. data/test/fixtures/create_comment +24 -0
  29. data/test/fixtures/github_commits +183 -0
  30. data/test/fixtures/kenmazaika +30 -0
  31. data/test/fixtures/pull_requests +151 -0
  32. data/test/mocks/git_client.rb +6 -0
  33. data/test/mocks/pull_request.rb +38 -0
  34. data/test/omg_pull_request/.gitkeep +0 -0
  35. data/test/test_helper.rb +53 -0
  36. data/test/units/omg_pull_request/aws/store_test.rb +22 -0
  37. data/test/units/omg_pull_request/github_wrapper_test.rb +43 -0
  38. data/test/units/omg_pull_request/lolcommits_test.rb +42 -0
  39. data/test/units/omg_pull_request/notifications_test.rb +125 -0
  40. data/test/units/omg_pull_request/prowl_test.rb +51 -0
  41. data/test/units/omg_pull_request/test_runner/base_test.rb +58 -0
  42. metadata +183 -0
@@ -0,0 +1,39 @@
1
+ module OmgPullRequest
2
+ class Lolcommits
3
+ LOLCOMMITS_PATH = '/animated_gifs'
4
+ LOLCOMMITS_URL = "http://www.lolcommits.com"
5
+ attr_accessor :configuration, :github_wrapper, :runner, :context
6
+
7
+ def initialize(attributes=Hash.new)
8
+ attributes.each do |attr, value|
9
+ self.send("#{attr}=", value)
10
+ end
11
+ end
12
+
13
+ def animation_url
14
+ return @animation_url if @animation_url
15
+ commits = github_wrapper.commit_shas(runner.pull_request) -
16
+ context.get_animated_shas(runner.pull_request.number)
17
+ context.add_animated_shas(runner.pull_request.number, commits)
18
+
19
+ @animation_url ||= get_animation_url(commits)
20
+ end
21
+
22
+ protected
23
+
24
+ def get_animation_url(shas)
25
+ unless shas.blank?
26
+ response = lolcommits_connection.post LOLCOMMITS_PATH, :animated_gif => { :shas => shas.join(',') }
27
+ JSON.parse(response.body).fetch("image").fetch("url") if response.status == 200
28
+ end
29
+ end
30
+
31
+ def lolcommits_connection
32
+ @lolcommits_connection ||= Faraday.new(:url => LOLCOMMITS_URL) do |f|
33
+ f.request :url_encoded
34
+ f.adapter Faraday.default_adapter
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,66 @@
1
+ module OmgPullRequest
2
+ module Notifications
3
+ protected
4
+ # GITHUB
5
+ def make_comment_success!(output_file)
6
+ github_comment(t("completed.github.success", runner_hash(:output_file => output_file)))
7
+ end
8
+
9
+ def make_comment_failure!(output_file)
10
+ github_comment(t("completed.github.failure", runner_hash(:output_file => output_file)))
11
+ end
12
+
13
+ def make_comment_conflict!
14
+ github_comment(t("error.github.conflict", runner_hash))
15
+ self.log(t("error.github.conflict", runner_hash))
16
+ end
17
+
18
+ def make_comment_test_running!
19
+ lol_url = lolcommits_client.animation_url
20
+ message = t("start.github.message", runner_hash)
21
+ message = t("start.github.lolcommits.message", runner_hash(:animation_url => lol_url)) if lol_url
22
+ github_comment(message)
23
+ end
24
+
25
+ # PROWL
26
+ def prowl_alert_success!
27
+ message = t("completed.prowl.success", runner_hash)
28
+ self.prowl_client.alert_all_relevant_people!(message, :success)
29
+ end
30
+
31
+ def prowl_alert_failure!
32
+ message = t("completed.prowl.failure", runner_hash)
33
+ self.prowl_client.alert_author!(message, :failure)
34
+ end
35
+
36
+
37
+ def process_output!
38
+ output_file = store_logger_data!
39
+ if self.success?
40
+ make_comment_success!(output_file)
41
+ prowl_alert_success!
42
+ else
43
+ make_comment_failure!(output_file)
44
+ prowl_alert_failure!
45
+ end
46
+ end
47
+
48
+ def github_comment(message)
49
+ GITHUB_WRAPPER.make_comment(self.issue_number, message)
50
+ end
51
+
52
+ def runner_hash(also=Hash.new)
53
+ also.merge({
54
+ :abbr_from_sha => abbr_from_sha,
55
+ :abbr_to_sha => abbr_to_sha,
56
+ :minutes => runtime_minutes,
57
+ :seconds => runtime_seconds,
58
+ :issue_number => issue_number,
59
+ :title => pull_request.title
60
+ })
61
+ end
62
+
63
+ public
64
+
65
+ end
66
+ end
@@ -0,0 +1,77 @@
1
+ module OmgPullRequest
2
+ class Prowl
3
+ PROWL_URL = 'https://api.prowlapp.com'
4
+ PROWL_PATH = '/publicapi/add'
5
+
6
+ attr_accessor :configuration, :logger, :runner, :github_wrapper
7
+
8
+ def initialize(attributes=Hash.new)
9
+ attributes.each do |attr, value|
10
+ self.send("#{attr}=", value)
11
+ end
12
+ end
13
+
14
+ def notify_users(msg, keys=[], options={})
15
+ return if keys.blank?
16
+
17
+ opts = {
18
+ :application => prowl_application,
19
+ :event => "notification",
20
+ :description => msg
21
+ }.merge( options )
22
+
23
+ keys.each do |key|
24
+ open_connection.post PROWL_PATH, opts.merge(:apikey => key)
25
+ end
26
+ end
27
+
28
+ def alert_all_relevant_people!(message, event)
29
+ notify_users(message, all_keys, {
30
+ :url => runner.pull_request.html_url,
31
+ :event => event
32
+ } )
33
+ end
34
+
35
+ def alert_author!(message, event)
36
+ notify_users(message, author_keys, {
37
+ :url => runner.pull_request.html_url,
38
+ :event => event
39
+ })
40
+ end
41
+
42
+ private
43
+
44
+ def keys_for_users(users=[])
45
+ users.collect { |u| (prowl_keys || {})[u] }.compact.uniq
46
+ end
47
+
48
+ def author_keys
49
+ author_logins = github_wrapper.author_logins(runner.pull_request)
50
+ keys_for_users(author_logins)
51
+ end
52
+
53
+ def all_keys
54
+ logins = github_wrapper.all_logins(runner.pull_request) +
55
+ runner.git_client.committers(runner.from_sha, runner.to_sha)
56
+
57
+ keys_for_users(logins)
58
+ end
59
+
60
+ def open_connection
61
+ @open_connection ||= Faraday.new(:url => PROWL_URL) do |f|
62
+ f.request :url_encoded
63
+ f.adapter Faraday.default_adapter
64
+ end
65
+ end
66
+
67
+ extend Configuration::Helpers
68
+ delegate_config_to(:configuration, :prowl)
69
+
70
+ [:application, :keys].each do |attr|
71
+ define_method "prowl_#{attr}" do
72
+ (prowl || Hash.new)[attr.to_s]
73
+ end
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,20 @@
1
+ module OmgPullRequest
2
+ class TestLogger
3
+ attr_accessor :store, :buffer
4
+ def initialize(attributes={})
5
+ attributes.each do |attr, value|
6
+ self.send("#{attr}=", value)
7
+ end
8
+ end
9
+
10
+ def log(output)
11
+ puts output
12
+ self.buffer = "#{buffer}\n#{output}"
13
+ end
14
+
15
+ def store_logs!(file_name)
16
+ self.store.store(StringIO.new(buffer), file_name)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ module OmgPullRequest
2
+ module TestRunner
3
+ def self.start_daemon
4
+ while(true)
5
+ begin
6
+ GITHUB_WRAPPER.pull_requests.each do |pr|
7
+ runner = CONFIGURATION.runner_class.new(:configuration => CONFIGURATION, :pull_request => pr)
8
+ next if CONTEXT.ran?(runner.request_sha)
9
+ CONTEXT.ran(runner.request_sha)
10
+
11
+ runner.run
12
+ end
13
+
14
+ rescue => ex
15
+ puts "An Error Occured: #{ex.inspect}\n#{ex.backtrace}"
16
+ end
17
+
18
+ sleep(60)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,128 @@
1
+ module OmgPullRequest
2
+ module TestRunner
3
+ class Base
4
+ attr_accessor :success, :runtime, :pull_request, :configuration
5
+ include Notifications
6
+
7
+ def initialize(attributes={})
8
+ attributes.each do |attr, value|
9
+ self.send("#{attr}=", value)
10
+ end
11
+ self.success = false
12
+ end
13
+
14
+ [:setup, :execute_tests, :teardown].each do |method|
15
+ define_method method do; true; end;
16
+ end
17
+
18
+ def run
19
+ log_test_details!
20
+ make_comment_test_running!
21
+
22
+ git_client.checkout!(from_sha)
23
+ merge_response = git_client.merge!(to_sha)
24
+
25
+ if merge_response == :conflict
26
+ make_comment_conflict!
27
+ return
28
+ end
29
+
30
+ Bundler.with_original_env do
31
+ setup
32
+
33
+ t = Time.now
34
+ self.success = execute_tests
35
+ self.runtime = Time.now - t
36
+
37
+ teardown
38
+ end
39
+
40
+ process_output!
41
+ end
42
+
43
+ def success?
44
+ self.success
45
+ end
46
+
47
+ def runtime_minutes
48
+ (runtime.to_f / 60).to_i
49
+ end
50
+
51
+ def runtime_seconds
52
+ (runtime.to_f % 60).round(3)
53
+ end
54
+
55
+ def from_sha
56
+ pull_request.base.sha
57
+ end
58
+
59
+ def to_sha
60
+ pull_request.head.sha
61
+ end
62
+
63
+ def request_sha
64
+ "#{self.from_sha}:#{self.to_sha}"
65
+ end
66
+
67
+ def abbr_from_sha
68
+ self.from_sha[0, 8]
69
+ end
70
+
71
+ def abbr_to_sha
72
+ self.to_sha[0, 8]
73
+ end
74
+
75
+ def issue_number
76
+ pull_request.number
77
+ end
78
+
79
+ def logger
80
+ @logger ||= TestLogger.new(:store => STORE)
81
+ end
82
+
83
+ def prowl_client
84
+ @prowl_client ||= Prowl.new(:configuration => CONFIGURATION, :logger => logger, :runner => self, :github_wrapper => GITHUB_WRAPPER)
85
+ end
86
+
87
+ def lolcommits_client
88
+ @lolcommits ||= Lolcommits.new(:configuration => CONFIGURATION, :github_wrapper => GITHUB_WRAPPER, :runner => self, :context => CONTEXT)
89
+ end
90
+
91
+ def git_client
92
+ @git_client ||= GitClient.new(:logger => logger, :configuration => CONFIGURATION)
93
+ end
94
+
95
+ def notifier
96
+ @notifier ||= Notifier.new(:runner => self, :github_wrapper => GITHUB_WRAPPER)
97
+ end
98
+
99
+ def log(message)
100
+ logger.log(message)
101
+ end
102
+
103
+ protected
104
+ # execute shell command, return true if success
105
+ def execute!(command)
106
+ log `#{command}`
107
+ exit_code = $?.to_i
108
+ success = exit_code == 0
109
+ end
110
+
111
+ def log_test_details!
112
+ log t("start.banner", runner_hash(:version => VERSION))
113
+ end
114
+
115
+ def store_logger_data!
116
+ logger.store_logs!("#{abbr_from_sha}-#{abbr_to_sha}-#{Time.now.to_i}.txt")
117
+ end
118
+
119
+ extend Configuration::Helpers
120
+ delegate_config_to(:configuration, :local_repo, :database_yml)
121
+
122
+ def t(key, options=Hash.new)
123
+ I18n.t(key, options)
124
+ end
125
+
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,19 @@
1
+ module OmgPullRequest
2
+ module TestRunner
3
+ class Rails < TestRunner::Base
4
+ def setup
5
+ execute!("cd #{local_repo} && cp #{database_yml} config/database.yml && bundle")
6
+ execute!("cd #{local_repo} && bundle exec rake db:drop:all && rake db:create:all && bundle exec rake db:schema:load")
7
+ end
8
+
9
+ def execute_tests
10
+ return execute!("cd #{local_repo} && bundle exec rake")
11
+ end
12
+
13
+ def teardown
14
+ execute!("rm #{local_repo}/log/test.log")
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ module OmgPullRequest
2
+ module TestRunner
3
+ class Ruby < TestRunner::Base
4
+ def execute_tests
5
+ return execute!("cd #{local_repo} && rake")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module OmgPullRequest
2
+ VERSION = "0.0.6"
3
+ end
data/locales/en.yml ADDED
@@ -0,0 +1,23 @@
1
+ en:
2
+ error:
3
+ github:
4
+ conflict: "### Unable To Run \nA conflict prevented the test suite from being run. Please manually resolve the conflict and the tests will be rerun.\nFrom `%{abbr_from_sha}` to `%{abbr_to_sha}`"
5
+
6
+ start:
7
+ banner: "OmgPullRequest %{version}\n
8
+ From: %{abbr_from_sha}\n
9
+ To: %{abbr_to_sha}\n
10
+ Issue Number: %{issue_number}"
11
+ github:
12
+ message: ":trollface: Running tests: `%{abbr_from_sha}` to `%{abbr_to_sha}`"
13
+ lolcommits:
14
+ message: ":trollface: Running tests: `%{abbr_from_sha}` to `%{abbr_to_sha}\n\nThis is what hard work looks like\n![Pretty Pictures](%{animation_url})"
15
+
16
+ completed:
17
+ github:
18
+ success: ":thumbsup: :shipit: \n### Tests Passed \nFrom `%{abbr_from_sha}` to `%{abbr_to_sha}`\nTests took %{minutes} minutes, %{seconds} seconds.\n[results](%{output_file})"
19
+ failure: ":thumbsdown: :fire: :broken_heart: \n### Tests Failed \n `%{abbr_from_sha}` to `%{abbr_to_sha}`\nTests too %{minutes} minutes, %{seconds} seconds.\n[results](%{output_file})"
20
+ prowl:
21
+ success: "Thumbs up, bro.\nPull request #%{issue_number}\n%{title}\nTests took %{minutes} minutes, %{seconds} seconds."
22
+ failure: "Sad face to the max, homie.\nPull request #%{issue_number}\n%{title}\nTests took %{minutes} minutes, %{seconds} seconds."
23
+
data/locales/omg.yml ADDED
@@ -0,0 +1,20 @@
1
+ omg:
2
+ error:
3
+ github:
4
+ conflict: "OMG"
5
+
6
+ start:
7
+ banner: "OMG"
8
+ github:
9
+ message: "OMG"
10
+ lolcommits:
11
+ message: "OMG"
12
+
13
+ completed:
14
+ github:
15
+ success: "OMG"
16
+ failure: "OMG"
17
+ prowl:
18
+ success: "OMG"
19
+ failure: "OMG"
20
+
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/omg_pull_request/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Ken Mazaika", "Jean Charles Sisk", "Master William Desmarais", "Ian Asaff"]
6
+ gem.email = ["kenmazaika@gmail.com"]
7
+ gem.description = %q{Have tests run automatically for your Github Pull Request}
8
+ gem.summary = %q{Have tests run automatically for your Github Pull Request}
9
+ gem.homepage = "http://github.com/where/omg_pull_request"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "omg_pull_request"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = OmgPullRequest::VERSION
17
+
18
+ gem.add_runtime_dependency(%q<aws-s3>, ">= 0.6.3")
19
+ gem.add_runtime_dependency(%q<faraday>, ">= 0.8.4")
20
+ gem.add_runtime_dependency(%q<github_api>, ">= 0.6.5")
21
+ gem.add_runtime_dependency(%q<uuid>, ">= 2.3.5")
22
+ gem.add_runtime_dependency(%q<rake>, ">= 0.9.2.2")
23
+ gem.add_runtime_dependency(%q<activesupport>, ">= 3.2.8")
24
+ gem.add_runtime_dependency(%q<i18n>, ">= 0.6.0")
25
+
26
+ end