omg_pull_request 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +47 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +68 -0
- data/LICENSE +22 -0
- data/README.md +66 -0
- data/Rakefile +12 -0
- data/bin/omg_pull_request +13 -0
- data/lib/omg_pull_request.rb +32 -0
- data/lib/omg_pull_request/aws/store.rb +30 -0
- data/lib/omg_pull_request/configuration.rb +55 -0
- data/lib/omg_pull_request/context.rb +29 -0
- data/lib/omg_pull_request/git_client.rb +31 -0
- data/lib/omg_pull_request/github_wrapper.rb +50 -0
- data/lib/omg_pull_request/lolcommits.rb +39 -0
- data/lib/omg_pull_request/notifications.rb +66 -0
- data/lib/omg_pull_request/prowl.rb +77 -0
- data/lib/omg_pull_request/test_logger.rb +20 -0
- data/lib/omg_pull_request/test_runner.rb +22 -0
- data/lib/omg_pull_request/test_runner/base.rb +128 -0
- data/lib/omg_pull_request/test_runner/rails.rb +19 -0
- data/lib/omg_pull_request/test_runner/ruby.rb +9 -0
- data/lib/omg_pull_request/version.rb +3 -0
- data/locales/en.yml +23 -0
- data/locales/omg.yml +20 -0
- data/omg_pull_request.gemspec +26 -0
- data/test/fixtures/comments +431 -0
- data/test/fixtures/config.yml +20 -0
- data/test/fixtures/create_comment +24 -0
- data/test/fixtures/github_commits +183 -0
- data/test/fixtures/kenmazaika +30 -0
- data/test/fixtures/pull_requests +151 -0
- data/test/mocks/git_client.rb +6 -0
- data/test/mocks/pull_request.rb +38 -0
- data/test/omg_pull_request/.gitkeep +0 -0
- data/test/test_helper.rb +53 -0
- data/test/units/omg_pull_request/aws/store_test.rb +22 -0
- data/test/units/omg_pull_request/github_wrapper_test.rb +43 -0
- data/test/units/omg_pull_request/lolcommits_test.rb +42 -0
- data/test/units/omg_pull_request/notifications_test.rb +125 -0
- data/test/units/omg_pull_request/prowl_test.rb +51 -0
- data/test/units/omg_pull_request/test_runner/base_test.rb +58 -0
- 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
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,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
|