fourchette 0.0.8 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Guardfile +2 -2
- data/README.md +32 -25
- data/fourchette.gemspec +2 -2
- data/lib/fourchette/github.rb +1 -1
- data/lib/fourchette/heroku.rb +13 -3
- data/lib/fourchette/pull_request.rb +10 -1
- data/lib/fourchette/version.rb +2 -2
- data/spec/lib/fourchette/fork_spec.rb +0 -28
- data/spec/lib/fourchette/github_spec.rb +127 -0
- data/spec/lib/fourchette/heroku_spec.rb +29 -4
- data/spec/lib/fourchette/pull_request_spec.rb +11 -5
- data/spec/lib/web/hooks_spec.rb +16 -0
- data/spec/lib/web/tarball_spec.rb +11 -17
- data/spec/support/sinatra_helper.rb +6 -0
- metadata +7 -4
- data/Gemfile.lock.orig +0 -163
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52bb772d746a51596c9b3a1d9289b5e7cdb06a35
|
4
|
+
data.tar.gz: e46108905c240695480644c8570f12e8157d92b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efe7daf22b8f7a9c380bf5ab217d3e1a0919e62e7afd5e34f12b5554699c06fa59329961ef1fd5f2338653b6d0841a7959f8a5d97a05121e6e8de6ecfdf55e01
|
7
|
+
data.tar.gz: 9795df2566dacb92402c13b410e399d6038337215c9eea4d98c6f472005d9b2bb0046ac0117f72451446fc3bbfbbb6794ebfd039dc3dfde6a1bfa40553b8c6e3
|
data/Guardfile
CHANGED
data/README.md
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
<p align="center">
|
2
|
-
<a href="https://github.com/
|
2
|
+
<a href="https://github.com/rainforestapp/fourchette">
|
3
3
|
<img src="http://i.imgur.com/967yX36.png" alt="Fourchette" />
|
4
4
|
</a>
|
5
5
|
<br />
|
6
6
|
<b>Your new best friend for isolated testing environments on Heroku</b>
|
7
7
|
<br />
|
8
|
-
<a href="https://codeclimate.com/github/
|
9
|
-
<a href="https://travis-ci.org/
|
10
|
-
<a href='https://coveralls.io/r/
|
11
|
-
<a href="http://badge.fury.io/rb/fourchette"><img src="
|
8
|
+
<a href="https://codeclimate.com/github/rainforestapp/fourchette"><img src="http://img.shields.io/codeclimate/github/rainforestapp/fourchette.svg?style=flat" /></a>
|
9
|
+
<a href="https://travis-ci.org/rainforestapp/fourchette"><img src="http://img.shields.io/travis/rainforestapp/fourchette/master.svg?style=flat" /></a>
|
10
|
+
<a href='https://coveralls.io/r/rainforestapp/fourchette'><img src='http://img.shields.io/coveralls/rainforestapp/fourchette.svg?style=flat' alt='Coverage Status' /></a>
|
11
|
+
<a href="http://badge.fury.io/rb/fourchette"><img src="http://img.shields.io/gem/v/fourchette.svg?style=flat" alt="Gem Version" height="18"></a>
|
12
|
+
<a href="http://tip4commit.com/github/rainforestapp/fourchette"><img src="http://tip4commit.com/projects/874.svg"><a>
|
12
13
|
</p>
|
13
14
|
|
14
|
-
Fourchette is your new best friend for having isolated testing
|
15
|
+
Fourchette is your new best friend for having isolated testing environments. It will help you test your [@GitHub](https://github.com/github) PRs against a fork of one your [@Heroku](https://github.com/heroku) apps. You will have one Heroku app per PR now. Isn't that amazing? It will make testing way easier and you won't have the (maybe) broken code from other PRs on staging but only the code that requires testing.
|
16
|
+
|
17
|
+
Fourchette is maintained by [@jipiboily](https://github.com/jipiboily/)! You can see the other [contributors here](https://github.com/rainforestapp/fourchette/graphs/contributors).
|
15
18
|
|
16
19
|
**IMPORTANT: Please note that forking your Heroku app means it will copy the same addon plans and that you will pay for multiple apps and their addons. Watch out!**
|
17
20
|
|
@@ -21,7 +24,7 @@ Fourchette is your new best friend for having isolated testing environements. It
|
|
21
24
|
* [Configuration](#configuration)
|
22
25
|
* [Enable your Fourchette instance](#enable-your-fourchette-instance)
|
23
26
|
* [Enable, disable, update or delete the hook](#enable-disable-update-or-delete-the-hook)
|
24
|
-
* [Before & after steps
|
27
|
+
* [Before & after steps; aka callbacks](#before--after-steps-aka-callbacks)
|
25
28
|
- [Rake tasks](#rake-tasks)
|
26
29
|
- [Async processing note](#async-processing-note)
|
27
30
|
- [Contribute](#contribute)
|
@@ -30,14 +33,14 @@ Fourchette is your new best friend for having isolated testing environements. It
|
|
30
33
|
|
31
34
|
## How does that work exactly?
|
32
35
|
|
33
|
-
|
34
|
-
- Fourchette receives an event via GitHub Hooks
|
35
|
-
-
|
36
|
-
-
|
37
|
-
-
|
38
|
-
-
|
39
|
-
|
40
|
-
We use it a lot at [Rainforest QA](https://www.rainforestqa.com/). If you want to see a sample Fourchette app, here is one for you to look at: https://github.com/rainforestapp/
|
36
|
+
1. A PR is created against your GitHub project
|
37
|
+
- Fourchette then receives an event via GitHub Hooks:
|
38
|
+
- It [forks](https://devcenter.heroku.com/articles/fork-app) an environment making it available to you
|
39
|
+
- Any new commit against that PR will update the code
|
40
|
+
- Closing the PR will delete the forked app
|
41
|
+
- Re-opening the PR will re-create a fork
|
42
|
+
|
43
|
+
We use it a lot at [Rainforest QA](https://www.rainforestqa.com/). If you want to see a sample Fourchette app, here is one for you to look at: https://github.com/rainforestapp/rf-ourchette.
|
41
44
|
|
42
45
|
## Installation
|
43
46
|
|
@@ -46,15 +49,15 @@ We use it a lot at [Rainforest QA](https://www.rainforestqa.com/). If you want t
|
|
46
49
|
3. run `cd my-app-name` (replace app name, again)
|
47
50
|
4. run `git init && git add . && git commit -m "Initial commit :tada:"`
|
48
51
|
5. push to Heroku
|
49
|
-
6. configure the right
|
52
|
+
6. configure the right environment variables (see [#configuration](#configuration))
|
50
53
|
7. Enable your Fourchette instance
|
51
54
|
|
52
55
|
### Configuration
|
53
56
|
|
54
|
-
- `export FOURCHETTE_GITHUB_PROJECT="
|
55
|
-
- `export FOURCHETTE_GITHUB_USERNAME="
|
57
|
+
- `export FOURCHETTE_GITHUB_PROJECT="rainforestapp/fourchette"`
|
58
|
+
- `export FOURCHETTE_GITHUB_USERNAME="rainforestapp"`
|
56
59
|
- `export FOURCHETTE_GITHUB_PERSONAL_TOKEN='a token here...'` # You can create one here: https://github.com/settings/applications
|
57
|
-
- `export FOURCHETTE_HEROKU_API_KEY=
|
60
|
+
- `export FOURCHETTE_HEROKU_API_KEY="API key here"`
|
58
61
|
- `export FOURCHETTE_HEROKU_APP_TO_FORK='the name of the app to fork from'`
|
59
62
|
- `export FOURCHETTE_APP_URL="http://fourchette-app.herokuapp.com"`
|
60
63
|
- `export FOURCHETTE_HEROKU_APP_PREFIX="fourchette"` # This is basically to namespace your forks. In that example, they would be named "fourchette-pr-1234" where "1234" is the PR number. Beware, the name can't be more than 30 characters total! It will be changed to be lowercase only, so you should probably just use lowercase characters anyways.
|
@@ -67,11 +70,11 @@ run `bundle exec rake fourchette:enable`
|
|
67
70
|
|
68
71
|
### Enable, disable, update or delete the hook
|
69
72
|
|
70
|
-
`bundle exec rake -T` will tell you the rake tasks available. There are tasks to enable, disable or delete the GitHub hook to your Fourchette instance. There is also one to update the hook. That last one is mostly for development, if your local tunnel
|
73
|
+
`bundle exec rake -T` will tell you the rake tasks available. There are tasks to enable, disable or delete the GitHub hook to your Fourchette instance. There is also one to update the hook. That last one is mostly for development, if your local tunnel URL changed and you want to update the hook's URL.
|
71
74
|
|
72
75
|
### Before & after steps, aka, callbacks
|
73
76
|
|
74
|
-
You need to run steps before and/or after the creation of your new Heroku app? Let's say you want to run mirgations after deploying new code. There is a simple (and primitive) way of doing it. It might not be perfect but
|
77
|
+
You need to run steps before and/or after the creation of your new Heroku app? Let's say you want to run mirgations after deploying new code. There is a simple (and primitive) way of doing it. It might not be perfect but will work until there is a cleaner and more flexible way of doing so, if required.
|
75
78
|
|
76
79
|
Create a file in your project to override the `Fourchette::Callbacks` class and include it after Fourchette.
|
77
80
|
|
@@ -79,7 +82,7 @@ You just want to override the `before` or `after` methods of `Fourchette::Callba
|
|
79
82
|
|
80
83
|
## Rake tasks
|
81
84
|
|
82
|
-
```
|
85
|
+
```bash
|
83
86
|
rake fourchette:console # Brings up a REPL with the code loaded
|
84
87
|
rake fourchette:delete # This deletes the Fourchette hook
|
85
88
|
rake fourchette:disable # This disables Fourchette hook
|
@@ -87,9 +90,13 @@ rake fourchette:enable # This enables Fourchette hook
|
|
87
90
|
rake fourchette:update # This updates the Fourchette hook with the current URL of the app
|
88
91
|
```
|
89
92
|
|
93
|
+
## QA Skip
|
94
|
+
|
95
|
+
Adding `[qa skip]` to the title of your pull request will cause Fourchette to ignore the pull request. This is inspired by the `[ci skip]` directive that [various](http://docs.travis-ci.com/user/how-to-skip-a-build/) [ci tools](https://circleci.com/docs/skip-a-build) support.
|
96
|
+
|
90
97
|
## Async processing note
|
91
98
|
|
92
|
-
Fourchette uses [Sucker Punch](https://github.com/brandonhilkert/sucker_punch), "a single-process Ruby asynchronous processing library". No need for redis or extra processes. It also mean
|
99
|
+
Fourchette uses [Sucker Punch](https://github.com/brandonhilkert/sucker_punch), "a single-process Ruby asynchronous processing library". No need for redis or extra processes. It also mean you can run it for free on Heroku, if this is what you want.
|
93
100
|
|
94
101
|
## Contribute
|
95
102
|
|
@@ -108,6 +115,6 @@ If you want the maximum output in your GitHub comments, set this environment var
|
|
108
115
|
export DEBUG='true'
|
109
116
|
```
|
110
117
|
|
111
|
-
#
|
118
|
+
# Thanks to...
|
112
119
|
|
113
|
-
|
120
|
+
- [@jpsirois](https://github.com/jpsirois/) for the logo!
|
data/fourchette.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Jean-Philippe Boily"]
|
10
10
|
spec.email = ["j@jipi.ca"]
|
11
11
|
spec.summary = %q{Your new best friend for isolated testing environments on Heroku.}
|
12
|
-
spec.description = %q{Fourchette is your new best friend for having isolated testing
|
12
|
+
spec.description = %q{Fourchette is your new best friend for having isolated testing environment. It will help you test your GitHub PRs against a fork of one your Heroku apps. You will have one Heroku app per PR now. Isn't that amazing? It will make testing way easier and you won't have the (maybe) broken code from other PRs on staging but only the code that requires testing.}
|
13
13
|
spec.homepage = "https://github.com/jipiboily/fourchette"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_dependency "sinatra-contrib"
|
24
24
|
spec.add_dependency "octokit"
|
25
25
|
spec.add_dependency "git"
|
26
|
-
spec.add_dependency "heroku", "~> 3.9" # Deprecated, but best/easiest solution for
|
26
|
+
spec.add_dependency "heroku", "~> 3.9" # Deprecated, but best/easiest solution for pgbackups...
|
27
27
|
spec.add_dependency 'platform-api', '~> 0.2.0'
|
28
28
|
spec.add_dependency "sucker_punch"
|
29
29
|
spec.add_dependency "thor"
|
data/lib/fourchette/github.rb
CHANGED
data/lib/fourchette/heroku.rb
CHANGED
@@ -63,9 +63,13 @@ class Fourchette::Heroku
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def copy_pg from, to
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
if pg_enabled?(from)
|
67
|
+
logger.info "Copying Postgres's data from #{from} to #{to}"
|
68
|
+
backup = Fourchette::Pgbackups.new
|
69
|
+
backup.copy(from, to)
|
70
|
+
else
|
71
|
+
logger.info "Postgres not enabled on #{from}. Skipping data copy."
|
72
|
+
end
|
69
73
|
end
|
70
74
|
|
71
75
|
def copy_RACK_AND_RAILS_ENV_again(from, to)
|
@@ -84,4 +88,10 @@ class Fourchette::Heroku
|
|
84
88
|
end
|
85
89
|
environments
|
86
90
|
end
|
91
|
+
|
92
|
+
def pg_enabled?(app)
|
93
|
+
client.addon.list(app).any? do |addon|
|
94
|
+
addon['addon_service']['name'] == 'heroku-postgresql'
|
95
|
+
end
|
96
|
+
end
|
87
97
|
end
|
@@ -2,6 +2,8 @@ class Fourchette::PullRequest
|
|
2
2
|
include SuckerPunch::Job
|
3
3
|
|
4
4
|
def perform params
|
5
|
+
return if qa_skip?(params)
|
6
|
+
|
5
7
|
callbacks = Fourchette::Callbacks.new(params)
|
6
8
|
fork = Fourchette::Fork.new(params)
|
7
9
|
|
@@ -20,4 +22,11 @@ class Fourchette::PullRequest
|
|
20
22
|
|
21
23
|
callbacks.after_all
|
22
24
|
end
|
23
|
-
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def qa_skip? params
|
29
|
+
params['pull_request']['title'].downcase.include?('[qa skip]')
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/lib/fourchette/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Fourchette
|
2
|
-
VERSION = "0.0
|
3
|
-
end
|
2
|
+
VERSION = "0.1.0"
|
3
|
+
end
|
@@ -22,34 +22,6 @@ describe Fourchette::Fork do
|
|
22
22
|
})
|
23
23
|
end
|
24
24
|
|
25
|
-
describe '#update' do
|
26
|
-
before do
|
27
|
-
subject.stub(:create_unless_exists)
|
28
|
-
subject.stub(:monitor_build)
|
29
|
-
Fourchette::Heroku.any_instance.stub_chain(:client, :build, :create)
|
30
|
-
end
|
31
|
-
|
32
|
-
after do
|
33
|
-
# subject.update
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'calls #create_unless_exists' do
|
37
|
-
subject.should_receive(:create_unless_exists)
|
38
|
-
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'starts the build process with the generated tarball URL' do
|
42
|
-
heroku_client_stub = double
|
43
|
-
heroku_client_stub.stub(:build)
|
44
|
-
heroku_client_stub.build.should_receive(:create)
|
45
|
-
Fourchette::Heroku.any_instance.stub(:client).and_return(heroku_client_stub)
|
46
|
-
subject.update
|
47
|
-
end
|
48
|
-
|
49
|
-
it 'starts monitoring the build' do
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
25
|
describe '#create' do
|
54
26
|
it 'calls #update and #create_unless_exists' do
|
55
27
|
subject.should_receive(:create_unless_exists)
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Fourchette::GitHub do
|
4
|
+
subject { described_class.new }
|
5
|
+
|
6
|
+
let(:fake_hooks) { [] }
|
7
|
+
|
8
|
+
let(:fake_hook) do
|
9
|
+
hook = double("hook")
|
10
|
+
hook.stub(:config).and_return(nil)
|
11
|
+
hook.stub(:id).and_return(123)
|
12
|
+
hook
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:fake_fourchette_hook) do
|
16
|
+
fake_hook.config.stub(:fourchette_env).and_return("something")
|
17
|
+
fake_hook
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:fake_enabled_fourchette_hook) do
|
21
|
+
fake_fourchette_hook.stub(:active).and_return(true)
|
22
|
+
fake_fourchette_hook
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:fake_disabled_fourchette_hook) do
|
26
|
+
fake_fourchette_hook.stub(:active).and_return(false)
|
27
|
+
fake_fourchette_hook
|
28
|
+
end
|
29
|
+
|
30
|
+
before do
|
31
|
+
allow_message_expectations_on_nil
|
32
|
+
subject.stub(:hooks).and_return(fake_hooks)
|
33
|
+
Octokit::Client.any_instance.stub(:edit_hook)
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#enable_hook" do
|
37
|
+
context "when there is alerady a Fourchette hook" do
|
38
|
+
|
39
|
+
context "when the hook was enabled" do
|
40
|
+
let(:fake_hooks) { [fake_enabled_fourchette_hook] }
|
41
|
+
|
42
|
+
it "does NOT enable the hook" do
|
43
|
+
Octokit::Client.any_instance.should_not_receive(:edit_hook)
|
44
|
+
|
45
|
+
subject.enable_hook
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when the hook was disabled" do
|
50
|
+
let(:fake_hooks) { [fake_disabled_fourchette_hook] }
|
51
|
+
|
52
|
+
it "enables the hook" do
|
53
|
+
Octokit::Client.any_instance.should_receive(:edit_hook)
|
54
|
+
|
55
|
+
subject.enable_hook
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when there is no Fourchette hook yet" do
|
61
|
+
it "adds a hook" do
|
62
|
+
Octokit::Client.any_instance.should_receive(:create_hook)
|
63
|
+
|
64
|
+
subject.enable_hook
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#disable_hook" do
|
70
|
+
context "where there is an active Fourchette hook" do
|
71
|
+
let(:fake_hooks) { [fake_enabled_fourchette_hook] }
|
72
|
+
|
73
|
+
it "disables the hook" do
|
74
|
+
Octokit::Client.any_instance.should_receive(:edit_hook)
|
75
|
+
|
76
|
+
subject.disable_hook
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when there is a disabled Fourchette hook" do
|
81
|
+
let(:fake_hooks) { [fake_disabled_fourchette_hook] }
|
82
|
+
it "does not try to disable a hook" do
|
83
|
+
subject.should_not_receive(:disable)
|
84
|
+
subject.disable_hook
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "when there is no Fourchette hook" do
|
89
|
+
it "does not try to disable a hook" do
|
90
|
+
subject.should_not_receive(:disable)
|
91
|
+
subject.disable_hook
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#update_hook" do
|
97
|
+
let(:fake_hooks) { [fake_enabled_fourchette_hook] }
|
98
|
+
|
99
|
+
it "calls toggle_active_state_to" do
|
100
|
+
subject
|
101
|
+
.should_receive(:toggle_active_state_to)
|
102
|
+
subject.update_hook
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#delete_hook" do
|
107
|
+
it "deletes the hook on GitHub" do
|
108
|
+
subject.stub(:fourchette_hook).and_return(fake_hook)
|
109
|
+
Octokit::Client.any_instance.should_receive(:remove_hook)
|
110
|
+
|
111
|
+
subject.delete_hook
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "#comment_pr" do
|
116
|
+
before do
|
117
|
+
stub_const("ENV", "FOURCHETTE_GITHUB_PROJECT" => "my-project")
|
118
|
+
end
|
119
|
+
|
120
|
+
it "adds a comment" do
|
121
|
+
Octokit::Client.any_instance
|
122
|
+
.should_receive(:add_comment).with("my-project", 1, "yo!")
|
123
|
+
|
124
|
+
subject.comment_pr(1, "yo!")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -93,7 +93,7 @@ describe Fourchette::Heroku do
|
|
93
93
|
let(:addon_list) { [ { 'plan' => { 'name' => 'redistogo' } } ] }
|
94
94
|
|
95
95
|
before do
|
96
|
-
heroku.client.stub(:addon).and_return(
|
96
|
+
heroku.client.stub(:addon).and_return(double('addon'))
|
97
97
|
heroku.client.addon.stub(:create)
|
98
98
|
heroku.client.addon.stub(:list).and_return(addon_list)
|
99
99
|
end
|
@@ -110,9 +110,34 @@ describe Fourchette::Heroku do
|
|
110
110
|
end
|
111
111
|
|
112
112
|
describe '#copy_pg' do
|
113
|
-
|
114
|
-
|
115
|
-
heroku.
|
113
|
+
|
114
|
+
before do
|
115
|
+
heroku.client.stub(:addon).and_return(double('addon'))
|
116
|
+
heroku.client.addon.stub(:list).and_return(addon_list)
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'when a heroku-postgresql addon is enabled' do
|
120
|
+
let(:addon_list) { [{ 'addon_service' => { 'name' => 'heroku-postgresql' } }] }
|
121
|
+
|
122
|
+
it 'calls Fourchette::Pgbackups#copy' do
|
123
|
+
Fourchette::Pgbackups.any_instance.should_receive(:copy).with(from_app_name, to_app_name)
|
124
|
+
heroku.copy_pg(from_app_name, to_app_name)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'when a heroku-postgresql addon is not enabled' do
|
129
|
+
let(:addon_list) { [{ 'addon_service' => { 'name' => 'redistogo' } }] }
|
130
|
+
|
131
|
+
it 'does not call Fourchette::Pgbackups#copy' do
|
132
|
+
# Had to work around lack of support for any_instance and should_not_receive
|
133
|
+
# see https://github.com/rspec/rspec-mocks/issues/164 for more details
|
134
|
+
count = 0
|
135
|
+
Fourchette::Pgbackups.any_instance.stub(:copy) do |from_app_name, to_app_name|
|
136
|
+
count += 1
|
137
|
+
end
|
138
|
+
heroku.copy_pg(from_app_name, to_app_name)
|
139
|
+
count.should eq(0)
|
140
|
+
end
|
116
141
|
end
|
117
142
|
end
|
118
143
|
|
@@ -11,27 +11,33 @@ describe Fourchette::PullRequest do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
context 'action == synchronize' do
|
14
|
-
let!(:params) { { 'action' => 'synchronize' } }
|
14
|
+
let!(:params) { { 'action' => 'synchronize', 'pull_request' => { 'title' => 'Test Me' } } }
|
15
15
|
|
16
16
|
it { fork.should_receive(:update) }
|
17
17
|
end
|
18
18
|
|
19
19
|
context 'action == closed' do
|
20
|
-
let!(:params) { { 'action' => 'closed' } }
|
20
|
+
let!(:params) { { 'action' => 'closed', 'pull_request' => { 'title' => 'Test Me' } } }
|
21
21
|
|
22
22
|
it { fork.should_receive(:delete) }
|
23
23
|
end
|
24
24
|
|
25
25
|
context 'action == reopened' do
|
26
|
-
let!(:params) { { 'action' => 'reopened' } }
|
26
|
+
let!(:params) { { 'action' => 'reopened', 'pull_request' => { 'title' => 'Test Me' } } }
|
27
27
|
|
28
28
|
it { fork.should_receive(:create) }
|
29
29
|
end
|
30
30
|
|
31
31
|
context 'action == opened' do
|
32
|
-
let!(:params) { { 'action' => 'opened' } }
|
32
|
+
let!(:params) { { 'action' => 'opened', 'pull_request' => { 'title' => 'Test Me' } } }
|
33
33
|
|
34
34
|
it { fork.should_receive(:create) }
|
35
35
|
end
|
36
|
+
|
37
|
+
context 'title includes [qa skip]' do
|
38
|
+
let!(:params) { { 'action' => 'opened', 'pull_request' => { 'title' => 'Skip Me [QA Skip]' } } }
|
39
|
+
|
40
|
+
it { fork.should_not_receive(:create) }
|
41
|
+
end
|
36
42
|
end
|
37
|
-
end
|
43
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "support/sinatra_helper"
|
3
|
+
require "sucker_punch/testing/inline"
|
4
|
+
|
5
|
+
describe "GitHub web hooks receiver" do
|
6
|
+
it "kicks an async job doing all the work" do
|
7
|
+
expected_param = { "something" => "ok" }
|
8
|
+
Fourchette::PullRequest.any_instance
|
9
|
+
.should_receive(:perform)
|
10
|
+
.with(expected_param)
|
11
|
+
|
12
|
+
post "/hooks",
|
13
|
+
expected_param.to_json,
|
14
|
+
"CONTENT_TYPE" => "application/json"
|
15
|
+
end
|
16
|
+
end
|
@@ -1,35 +1,29 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "spec_helper"
|
2
|
+
require "support/sinatra_helper"
|
3
3
|
|
4
|
-
describe
|
5
|
-
|
6
|
-
|
7
|
-
def app
|
8
|
-
Sinatra::Application
|
9
|
-
end
|
10
|
-
|
11
|
-
context 'valid and not expired URL' do
|
4
|
+
describe "web tarball serving" do
|
5
|
+
context "valid and not expired URL" do
|
12
6
|
it "returns the file" do
|
13
7
|
expire_in_2_secs = Time.now.to_i + 2
|
14
8
|
Fourchette::Tarball.any_instance
|
15
9
|
.should_receive(:filepath)
|
16
|
-
.with(
|
10
|
+
.with("1234567", expire_in_2_secs.to_s)
|
17
11
|
.and_return { "#{Dir.pwd}/spec/factories/fake_file" }
|
18
|
-
|
12
|
+
|
19
13
|
get "/jipiboily/fourchette/1234567/#{expire_in_2_secs}"
|
20
|
-
expect(last_response.headers[
|
21
|
-
expect(last_response.body).to eq
|
14
|
+
expect(last_response.headers["Content-Type"]).to eq "application/x-tgz"
|
15
|
+
expect(last_response.body).to eq "some content..."
|
22
16
|
end
|
23
17
|
end
|
24
18
|
|
25
|
-
context
|
19
|
+
context "expired URL" do
|
26
20
|
it "does NOT returns the file if it is expired" do
|
27
21
|
expired_one_sec_ago = Time.now.to_i - 1
|
28
22
|
get "/jipiboily/fourchette/1234567/#{expired_one_sec_ago}"
|
29
23
|
expect(last_response).not_to be_ok
|
30
|
-
expect(last_response.body).not_to eq(
|
24
|
+
expect(last_response.body).not_to eq("Hello World")
|
31
25
|
expect(last_response.status).to eq(404)
|
32
26
|
subject.should_not_receive(:send_file)
|
33
27
|
end
|
34
28
|
end
|
35
|
-
end
|
29
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fourchette
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean-Philippe Boily
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -220,7 +220,7 @@ dependencies:
|
|
220
220
|
- - ">="
|
221
221
|
- !ruby/object:Gem::Version
|
222
222
|
version: '0'
|
223
|
-
description: Fourchette is your new best friend for having isolated testing
|
223
|
+
description: Fourchette is your new best friend for having isolated testing environment.
|
224
224
|
It will help you test your GitHub PRs against a fork of one your Heroku apps. You
|
225
225
|
will have one Heroku app per PR now. Isn't that amazing? It will make testing way
|
226
226
|
easier and you won't have the (maybe) broken code from other PRs on staging but
|
@@ -235,7 +235,6 @@ files:
|
|
235
235
|
- ".gitignore"
|
236
236
|
- ".travis.yml"
|
237
237
|
- Gemfile
|
238
|
-
- Gemfile.lock.orig
|
239
238
|
- Guardfile
|
240
239
|
- LICENSE.txt
|
241
240
|
- Procfile
|
@@ -265,9 +264,11 @@ files:
|
|
265
264
|
- spec/lib/fourchette/logger_spec.rb
|
266
265
|
- spec/lib/fourchette/pull_request_spec.rb
|
267
266
|
- spec/lib/fourchette/tarball_spec.rb
|
267
|
+
- spec/lib/web/hooks_spec.rb
|
268
268
|
- spec/lib/web/tarball_spec.rb
|
269
269
|
- spec/spec_helper.rb
|
270
270
|
- spec/support/silent-logger.rb
|
271
|
+
- spec/support/sinatra_helper.rb
|
271
272
|
- templates/Gemfile
|
272
273
|
- templates/Procfile
|
273
274
|
- templates/Rakefile
|
@@ -306,6 +307,8 @@ test_files:
|
|
306
307
|
- spec/lib/fourchette/logger_spec.rb
|
307
308
|
- spec/lib/fourchette/pull_request_spec.rb
|
308
309
|
- spec/lib/fourchette/tarball_spec.rb
|
310
|
+
- spec/lib/web/hooks_spec.rb
|
309
311
|
- spec/lib/web/tarball_spec.rb
|
310
312
|
- spec/spec_helper.rb
|
311
313
|
- spec/support/silent-logger.rb
|
314
|
+
- spec/support/sinatra_helper.rb
|
data/Gemfile.lock.orig
DELETED
@@ -1,163 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
fourchette (0.0.8)
|
5
|
-
git
|
6
|
-
heroku
|
7
|
-
octokit
|
8
|
-
platform-api (~> 0.2.0)
|
9
|
-
rake
|
10
|
-
sinatra
|
11
|
-
sinatra-contrib
|
12
|
-
sucker_punch
|
13
|
-
thor
|
14
|
-
|
15
|
-
GEM
|
16
|
-
remote: http://rubygems.org/
|
17
|
-
specs:
|
18
|
-
addressable (2.3.6)
|
19
|
-
backports (3.6.0)
|
20
|
-
byebug (2.7.0)
|
21
|
-
columnize (~> 0.3)
|
22
|
-
debugger-linecache (~> 1.2)
|
23
|
-
celluloid (0.15.2)
|
24
|
-
timers (~> 1.1.0)
|
25
|
-
celluloid-io (0.15.0)
|
26
|
-
celluloid (>= 0.15.0)
|
27
|
-
nio4r (>= 0.5.0)
|
28
|
-
coderay (1.1.0)
|
29
|
-
columnize (0.8.9)
|
30
|
-
coveralls (0.7.0)
|
31
|
-
multi_json (~> 1.3)
|
32
|
-
rest-client
|
33
|
-
simplecov (>= 0.7)
|
34
|
-
term-ansicolor
|
35
|
-
thor
|
36
|
-
debugger-linecache (1.2.0)
|
37
|
-
diff-lcs (1.2.5)
|
38
|
-
docile (1.1.3)
|
39
|
-
dotenv (0.7.0)
|
40
|
-
erubis (2.7.0)
|
41
|
-
excon (0.34.0)
|
42
|
-
faraday (0.9.0)
|
43
|
-
multipart-post (>= 1.2, < 3)
|
44
|
-
ffi (1.9.3)
|
45
|
-
foreman (0.64.0)
|
46
|
-
dotenv (~> 0.7.0)
|
47
|
-
thor (>= 0.13.6)
|
48
|
-
formatador (0.2.4)
|
49
|
-
git (1.2.6)
|
50
|
-
guard (2.5.1)
|
51
|
-
formatador (>= 0.2.4)
|
52
|
-
listen (~> 2.6)
|
53
|
-
lumberjack (~> 1.0)
|
54
|
-
pry (>= 0.9.12)
|
55
|
-
thor (>= 0.18.1)
|
56
|
-
guard-rspec (4.2.7)
|
57
|
-
guard (~> 2.1)
|
58
|
-
rspec (>= 2.14, < 4.0)
|
59
|
-
heroics (0.0.10)
|
60
|
-
erubis (~> 2.7.0)
|
61
|
-
excon
|
62
|
-
moneta
|
63
|
-
multi_json (>= 1.9.2)
|
64
|
-
netrc
|
65
|
-
heroku (3.8.2)
|
66
|
-
heroku-api (~> 0.3.17)
|
67
|
-
launchy (>= 0.3.2)
|
68
|
-
netrc (~> 0.7.7)
|
69
|
-
rest-client (~> 1.6.1)
|
70
|
-
rubyzip
|
71
|
-
heroku-api (0.3.18)
|
72
|
-
excon (~> 0.27)
|
73
|
-
multi_json (~> 1.8)
|
74
|
-
launchy (2.4.2)
|
75
|
-
addressable (~> 2.3)
|
76
|
-
listen (2.6.2)
|
77
|
-
celluloid (>= 0.15.2)
|
78
|
-
celluloid-io (>= 0.15.0)
|
79
|
-
rb-fsevent (>= 0.9.3)
|
80
|
-
rb-inotify (>= 0.9)
|
81
|
-
lumberjack (1.0.4)
|
82
|
-
method_source (0.8.2)
|
83
|
-
mime-types (2.2)
|
84
|
-
moneta (0.7.20)
|
85
|
-
multi_json (1.9.2)
|
86
|
-
multipart-post (2.0.0)
|
87
|
-
netrc (0.7.7)
|
88
|
-
nio4r (1.0.0)
|
89
|
-
octokit (3.1.0)
|
90
|
-
sawyer (~> 0.5.3)
|
91
|
-
platform-api (0.2.0)
|
92
|
-
heroics (~> 0.0.10)
|
93
|
-
pry (0.9.12.6)
|
94
|
-
coderay (~> 1.0)
|
95
|
-
method_source (~> 0.8)
|
96
|
-
slop (~> 3.4)
|
97
|
-
pry-byebug (1.3.2)
|
98
|
-
byebug (~> 2.7)
|
99
|
-
pry (~> 0.9.12)
|
100
|
-
puma (2.8.2)
|
101
|
-
rack (>= 1.1, < 2.0)
|
102
|
-
rack (1.5.2)
|
103
|
-
rack-protection (1.5.3)
|
104
|
-
rack
|
105
|
-
rack-test (0.6.2)
|
106
|
-
rack (>= 1.0)
|
107
|
-
rake (10.3.2)
|
108
|
-
rb-fsevent (0.9.4)
|
109
|
-
rb-inotify (0.9.3)
|
110
|
-
ffi (>= 0.5.0)
|
111
|
-
rest-client (1.6.7)
|
112
|
-
mime-types (>= 1.16)
|
113
|
-
rspec (2.14.1)
|
114
|
-
rspec-core (~> 2.14.0)
|
115
|
-
rspec-expectations (~> 2.14.0)
|
116
|
-
rspec-mocks (~> 2.14.0)
|
117
|
-
rspec-core (2.14.8)
|
118
|
-
rspec-expectations (2.14.5)
|
119
|
-
diff-lcs (>= 1.1.3, < 2.0)
|
120
|
-
rspec-mocks (2.14.6)
|
121
|
-
rubyzip (1.1.4)
|
122
|
-
sawyer (0.5.4)
|
123
|
-
addressable (~> 2.3.5)
|
124
|
-
faraday (~> 0.8, < 0.10)
|
125
|
-
simplecov (0.8.2)
|
126
|
-
docile (~> 1.1.0)
|
127
|
-
multi_json
|
128
|
-
simplecov-html (~> 0.8.0)
|
129
|
-
simplecov-html (0.8.0)
|
130
|
-
sinatra (1.4.5)
|
131
|
-
rack (~> 1.4)
|
132
|
-
rack-protection (~> 1.4)
|
133
|
-
tilt (~> 1.3, >= 1.3.4)
|
134
|
-
sinatra-contrib (1.4.2)
|
135
|
-
backports (>= 2.0)
|
136
|
-
multi_json
|
137
|
-
rack-protection
|
138
|
-
rack-test
|
139
|
-
sinatra (~> 1.4.0)
|
140
|
-
tilt (~> 1.3)
|
141
|
-
slop (3.5.0)
|
142
|
-
sucker_punch (1.0.5)
|
143
|
-
celluloid (~> 0.15.2)
|
144
|
-
term-ansicolor (1.3.0)
|
145
|
-
tins (~> 1.0)
|
146
|
-
terminal-notifier-guard (1.5.3)
|
147
|
-
thor (0.19.1)
|
148
|
-
tilt (1.4.1)
|
149
|
-
timers (1.1.0)
|
150
|
-
tins (1.1.0)
|
151
|
-
|
152
|
-
PLATFORMS
|
153
|
-
ruby
|
154
|
-
|
155
|
-
DEPENDENCIES
|
156
|
-
coveralls
|
157
|
-
foreman
|
158
|
-
fourchette!
|
159
|
-
guard-rspec
|
160
|
-
pry-byebug
|
161
|
-
puma
|
162
|
-
rspec (~> 2.14.1)
|
163
|
-
terminal-notifier-guard
|