omg_pull_request 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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
data/.gitignore ADDED
@@ -0,0 +1,47 @@
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile ~/.gitignore_global
6
+
7
+ # Ignore bundler config
8
+ /.bundle
9
+
10
+ # Ignore the default SQLite database.
11
+ /db/*.sqlite3
12
+
13
+ # Ignore all logfiles and tempfiles.
14
+ /log/*.log
15
+ /tmp
16
+ .DS_Store
17
+ *.rb.pid
18
+
19
+ # Assets are precompiled on deploy
20
+ /public/assets
21
+
22
+ # Coverage directory should not be checked in
23
+ /coverage
24
+
25
+ # PEOPLE WHO USE VIM ROCK!
26
+ *.swp
27
+ *.swo
28
+ .swp
29
+ .swo
30
+ *.swn
31
+ *.swm
32
+
33
+ test/functional/coverage/**
34
+ test/unit/coverage/**
35
+ test/functional/advertisers/coverage/**
36
+ .cache_rake_t
37
+ .idea/**
38
+ public/system
39
+ .sass-cache
40
+
41
+ # Allow using Turn for testing, but don't check in configuration
42
+ config/initializers/turn.rb
43
+ config/initializers/error_mass_assign.rb
44
+ config/initializers/activeresource_debug.rb
45
+ tags
46
+ .rbenv-version
47
+ test/omg_pull_request/config.yml
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'minitest'
7
+ gem 'fakeweb'
8
+ gem 'mocha'
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ omg_pull_request (0.0.6)
5
+ activesupport (>= 3.2.8)
6
+ aws-s3 (>= 0.6.3)
7
+ faraday (>= 0.8.4)
8
+ github_api (>= 0.6.5)
9
+ i18n (>= 0.6.0)
10
+ rake (>= 0.9.2.2)
11
+ uuid (>= 2.3.5)
12
+
13
+ GEM
14
+ remote: http://rubygems.org/
15
+ specs:
16
+ activesupport (3.2.8)
17
+ i18n (~> 0.6)
18
+ multi_json (~> 1.0)
19
+ aws-s3 (0.6.3)
20
+ builder
21
+ mime-types
22
+ xml-simple
23
+ builder (3.0.0)
24
+ fakeweb (1.3.0)
25
+ faraday (0.8.4)
26
+ multipart-post (~> 1.1)
27
+ github_api (0.6.5)
28
+ faraday (~> 0.8.1)
29
+ hashie (~> 1.2.0)
30
+ multi_json (~> 1.3)
31
+ nokogiri (~> 1.5.2)
32
+ oauth2
33
+ hashie (1.2.0)
34
+ httpauth (0.1)
35
+ i18n (0.6.0)
36
+ jwt (0.1.5)
37
+ multi_json (>= 1.0)
38
+ macaddr (1.6.1)
39
+ systemu (~> 2.5.0)
40
+ metaclass (0.0.1)
41
+ mime-types (1.19)
42
+ minitest (3.3.0)
43
+ mocha (0.11.4)
44
+ metaclass (~> 0.0.1)
45
+ multi_json (1.3.6)
46
+ multipart-post (1.1.5)
47
+ nokogiri (1.5.5)
48
+ oauth2 (0.8.0)
49
+ faraday (~> 0.8)
50
+ httpauth (~> 0.1)
51
+ jwt (~> 0.1.4)
52
+ multi_json (~> 1.0)
53
+ rack (~> 1.2)
54
+ rack (1.4.1)
55
+ rake (0.9.2.2)
56
+ systemu (2.5.2)
57
+ uuid (2.3.5)
58
+ macaddr (~> 1.0)
59
+ xml-simple (1.1.1)
60
+
61
+ PLATFORMS
62
+ ruby
63
+
64
+ DEPENDENCIES
65
+ fakeweb
66
+ minitest
67
+ mocha
68
+ omg_pull_request!
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Ken Mazaika
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ ## Omg! Pull Request!
2
+
3
+ Omg! Pull Request! is a daemon designed to easily run automated tests for a project that is hosted on GitHub on the submission of a pull request. On completion of the tests the daemon will make a comment on the pull request on the status of the test suite.
4
+
5
+ #### Goals
6
+
7
+ * Allow simple configuration for a standard rails project
8
+ * Support flexibilty and extensibility to work in non ruby/rails projects
9
+ * Reduce test failures caused by merging in code with broken tests
10
+
11
+ #### Non Goals
12
+
13
+ * Work with non-github environments
14
+
15
+
16
+ ### Integrations
17
+
18
+ The project integrates with a number of third party services to maximize usefulness / coolness.
19
+
20
+ #### Prowl
21
+
22
+ Prowl integration allows you to setup a phone to be alerted when the test suite completes. You will be alerted if you are the author, or have commited in the pull request.
23
+
24
+ #### Lolcommits
25
+
26
+ On running the test suite an animated gif can be generated of the lolcommits that were generated by the pull request. This feature was added for the lulz.
27
+
28
+ ## Installation
29
+
30
+ 1. In a rails project, add `omg_pull_request` to the Gemfile.
31
+ 2. Make an `omg_pull_request` directory in the project's `test` directory.
32
+ 3. Add a `database.yml` file in the `omg_pull_request` dir. This will drop databases, so it is suggested this points to different databases than the main `config/database.yml` file
33
+ 4. Create a github user to run the tests as. This user will need to have access to the repo the test is run on. It can be your developer account, or a new account specifically for this.
34
+ 5. Add a `config.yml` file in the `omg_pull_request` dir. It follows this template:
35
+
36
+ ```
37
+ repo_owner: kenmazaika
38
+ repo: pictures
39
+ locale: en
40
+ runner: Rails
41
+
42
+ github_credentials:
43
+ login: github_user
44
+ password: github_password
45
+
46
+ aws:
47
+ access_token: s3_token
48
+ secret_token: s3_secret
49
+ bucket: s3_bucket
50
+
51
+ prowl:
52
+ application: wherebot
53
+ keys:
54
+ kenmazaika: key
55
+ kenmazaika@gmail.com: key
56
+ ```
57
+
58
+ This is a sample config, with sensitive data scrubbed for running tests on the repo: https://github.com/kenmazaika/pictures. One important note is for the prowl integration it should contain a key for both the github user_name and the email address that can be pulled from git.
59
+
60
+ 6. On a server someplace clone the repo. This cloned repo will be managed by the daemon, and the tests will run on it from now on.
61
+ 7. In a screen session run `omg_pull_request`.
62
+ 8. Enjoy.
63
+
64
+ ### Example
65
+
66
+ You can see an example of a successful pull request that has been `omg_pull_request`ified here: https://github.com/where/omg_pull_request/pull/1.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+
5
+ include Rake::DSL
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.pattern = 'test/**/*_test.rb'
9
+ end
10
+ task :default => [:test]
11
+
12
+
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'omg_pull_request'
4
+
5
+ include OmgPullRequest
6
+ locale_dir = File.expand_path("../../locales", __FILE__)
7
+ I18n.load_path = [
8
+ File.join(locale_dir, "omg.yml"),
9
+ File.join(locale_dir, "en.yml")
10
+ ]
11
+ I18n.locale = CONFIGURATION.locale if CONFIGURATION.locale
12
+
13
+ TestRunner.start_daemon
@@ -0,0 +1,32 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+ require 'active_support/all'
4
+ require 'faraday'
5
+ require 'github_api'
6
+ require 'yaml'
7
+ require 'uuid'
8
+ require 'aws/s3'
9
+ require 'i18n'
10
+ require 'omg_pull_request/configuration'
11
+ require 'omg_pull_request/test_logger'
12
+ require 'omg_pull_request/aws/store'
13
+ require 'omg_pull_request/github_wrapper'
14
+ require 'omg_pull_request/notifications'
15
+ require 'omg_pull_request/test_runner'
16
+ require 'omg_pull_request/test_runner/base'
17
+ require 'omg_pull_request/test_runner/rails'
18
+ require 'omg_pull_request/test_runner/ruby'
19
+ require 'omg_pull_request/context'
20
+ require 'omg_pull_request/git_client'
21
+ require 'omg_pull_request/prowl'
22
+ require 'omg_pull_request/lolcommits'
23
+ require 'omg_pull_request/version'
24
+
25
+ module OmgPullRequest
26
+ CONFIGURATION = Configuration.new
27
+ STORE = Aws::Store.new(:storage_config => CONFIGURATION.aws.symbolize_keys)
28
+ CONTEXT = Context.new
29
+ GITHUB_WRAPPER = GithubWrapper.new(:configuration => CONFIGURATION)
30
+ end
31
+
32
+
@@ -0,0 +1,30 @@
1
+ module OmgPullRequest
2
+ module Aws
3
+ class Store
4
+ attr_accessor :storage_config
5
+ def initialize(attributes={})
6
+ attributes.each do |attr, value|
7
+ self.send("#{attr}=", value)
8
+ end
9
+
10
+ AWS::S3::Base.establish_connection!(
11
+ :access_key_id => access_token,
12
+ :secret_access_key => secret_token
13
+ )
14
+ end
15
+
16
+ def store(data, file_name)
17
+ AWS::S3::S3Object.store(file_name, data, bucket, :access => :public_read)
18
+ "http://s3.amazonaws.com/#{bucket}/#{file_name}"
19
+ end
20
+
21
+ private
22
+
23
+ [:access_token, :secret_token, :bucket].each do |attr|
24
+ define_method attr do
25
+ storage_config[attr]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,55 @@
1
+ module OmgPullRequest
2
+ class Configuration
3
+ attr_reader :config
4
+
5
+ def initialize(attributes={})
6
+ attributes.each do |attr, value|
7
+ self.send("#{attr}=", value)
8
+ end
9
+ @config = YAML.load(File.open(self.config_file))
10
+ end
11
+
12
+
13
+ [:repo_owner, :repo, :database_yml, :aws, :github_credentials,
14
+ :lolcommits_server_url, :prowl, :locale].each do |attr|
15
+ define_method attr do
16
+ self.config[attr.to_s]
17
+ end
18
+ end
19
+
20
+ def local_repo
21
+ self.config['local_repo'] || Dir.pwd
22
+ end
23
+
24
+ def database_yml
25
+ self.config['database_yml'] || File.join(omg_dir, 'database.yml')
26
+ end
27
+
28
+ def config_file
29
+ file = ENV['yml'] || File.join(omg_dir, 'config.yml')
30
+ unless File.exist?(file)
31
+ raise "Configuration file does not exist: #{file}"
32
+ end
33
+
34
+ file
35
+ end
36
+
37
+ def omg_dir
38
+ File.join(Dir.pwd, 'test/omg_pull_request')
39
+ end
40
+
41
+ def runner_class
42
+ "OmgPullRequest::TestRunner::#{config['runner'] || 'Rails'}".constantize
43
+ end
44
+
45
+ module Helpers
46
+ def delegate_config_to(config, *attrs)
47
+ attrs.each do |attr|
48
+ define_method attr do
49
+ self.send(config).send(attr)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,29 @@
1
+ module OmgPullRequest
2
+ class Context
3
+ def ran(request_sha)
4
+ ran_hash[request_sha] = true
5
+ end
6
+
7
+ def ran?(request_sha)
8
+ ran_hash[request_sha] == true
9
+ end
10
+
11
+ def get_animated_shas(issue_number)
12
+ animated_shas[issue_number] || []
13
+ end
14
+
15
+ def add_animated_shas(issue_number, shas)
16
+ animated_shas[issue_number] = get_animated_shas(issue_number) + shas
17
+ end
18
+
19
+ private
20
+
21
+ def ran_hash
22
+ @ran_hash ||= Hash.new
23
+ end
24
+
25
+ def animated_shas
26
+ @animated_sha || Hash.new
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+ module OmgPullRequest
2
+ class GitClient
3
+ attr_accessor :logger, :configuration
4
+
5
+ def initialize(attributes=Hash.new)
6
+ attributes.each do |attr, value|
7
+ self.send("#{attr}=", value)
8
+ end
9
+ end
10
+
11
+ def committers(from_sha, to_sha)
12
+ `cd #{local_repo} && git shortlog -sne #{from_sha}..#{to_sha} | awk '{ print $NF}' | cut -d'<' -f2 | cut -d'>' -f1`.split
13
+ end
14
+
15
+ def checkout!(sha)
16
+ logger.log `cd #{local_repo} && git reset --hard && git fetch && git checkout #{sha}`
17
+ end
18
+
19
+ def merge!(sha)
20
+ merge_response = `cd #{local_repo} && git merge #{sha}`
21
+ self.logger.log merge_response
22
+ merge_response.match(/CONFLICT/) ? :conflict : :success
23
+ end
24
+
25
+
26
+ private
27
+
28
+ extend Configuration::Helpers
29
+ delegate_config_to(:configuration, :local_repo)
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ module OmgPullRequest
2
+ class GithubWrapper
3
+ attr_accessor :configuration
4
+
5
+ def initialize(attributes={})
6
+ attributes.each do |attr, value|
7
+ self.send("#{attr}=", value)
8
+ end
9
+ end
10
+
11
+ def author_logins(pull_request)
12
+ [pull_request.user.login, github_client.users.get(:user => pull_request.user.login).email]
13
+ end
14
+
15
+ def all_logins(pull_request)
16
+ logins = [pull_request.user.login]
17
+
18
+ logins |= github_client.issues.comments.list(repo_owner, repo, pull_request.number).collect do |c|
19
+ c.user.login
20
+ end
21
+
22
+ logins.uniq
23
+ end
24
+
25
+ def commit_shas(pull_request)
26
+ commits = github_client.pull_requests.commits(repo_owner, repo, pull_request.number)
27
+
28
+ commits.collect do |commit|
29
+ commit.sha[0..10]
30
+ end
31
+ end
32
+
33
+ def make_comment(issue_number, body)
34
+ github_client.issues.comments.create(repo_owner, repo, issue_number, :body => body)
35
+ end
36
+
37
+ def pull_requests
38
+ github_client.pull_requests.list(repo_owner, repo)
39
+ end
40
+
41
+ private
42
+
43
+ extend Configuration::Helpers
44
+ delegate_config_to(:configuration, :repo_owner, :repo, :github_credentials)
45
+
46
+ def github_client
47
+ @github_client ||= Github.new(github_credentials.symbolize_keys)
48
+ end
49
+ end
50
+ end