git_reflow 0.3.5 → 0.4.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.
@@ -0,0 +1,146 @@
1
+ require 'spec_helper'
2
+
3
+ describe GitReflow::GitHelpers do
4
+ let(:origin_url) { 'git@github.com:reenhanced.spectacular/this-is-the.shit.git' }
5
+
6
+ before do
7
+ stub_with_fallback(GitReflow::Config, :get).with('remote.origin.url').and_return(origin_url)
8
+
9
+ module Gitacular
10
+ include GitReflow::GitHelpers
11
+ extend self
12
+ end
13
+
14
+ stub_run_for Gitacular
15
+ end
16
+
17
+ describe ".remote_user" do
18
+ subject { Gitacular.remote_user }
19
+
20
+ it { should == 'reenhanced.spectacular' }
21
+
22
+ context "remote origin url isn't set" do
23
+ let(:origin_url) { nil }
24
+ it { should == '' }
25
+ end
26
+ end
27
+
28
+ describe ".remote_repo_name" do
29
+ subject { Gitacular.remote_repo_name }
30
+
31
+ it { should == 'this-is-the.shit' }
32
+
33
+ context "remote origin url isn't set" do
34
+ let(:origin_url) { nil }
35
+ it { should == '' }
36
+ end
37
+ end
38
+
39
+ describe ".current_branch" do
40
+ subject { Gitacular.current_branch }
41
+ it { expect{ subject }.to have_run_command_silently "git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g'" }
42
+ end
43
+
44
+ describe ".get_first_commit_message" do
45
+ subject { Gitacular.get_first_commit_message }
46
+ it { expect{ subject }.to have_run_command_silently 'git log --pretty=format:"%s" --no-merges -n 1' }
47
+ end
48
+
49
+ describe ".push_current_branch" do
50
+ subject { Gitacular.push_current_branch }
51
+ before { Gitacular.stub(:current_branch).and_return('bingo') }
52
+ it { expect{ subject }.to have_run_command "git push origin bingo" }
53
+ end
54
+
55
+ describe ".fetch_destination(destination_branch)" do
56
+ subject { Gitacular.fetch_destination('new-feature') }
57
+ it { expect{ subject }.to have_run_command "git fetch origin new-feature" }
58
+ end
59
+
60
+ describe ".update_destination(destination_branch)" do
61
+ let(:current_branch) { 'bananas' }
62
+ let(:destination_branch) { 'monkey-business' }
63
+
64
+ before { Gitacular.stub(:current_branch).and_return(current_branch) }
65
+ subject { Gitacular.update_destination(destination_branch) }
66
+
67
+ it "updates the destination branch with the latest code from the remote repo" do
68
+ expect { subject }.to have_run_commands_in_order [
69
+ "git checkout #{destination_branch}",
70
+ "git pull origin #{destination_branch}",
71
+ "git checkout #{current_branch}"
72
+ ]
73
+ end
74
+ end
75
+
76
+ describe ".merge_feature_branch(options)" do
77
+ let(:destination_branch) { 'monkey-business' }
78
+ let(:feature_branch) { 'bananas' }
79
+ let(:merge_options) { {} }
80
+
81
+ subject { Gitacular.merge_feature_branch(feature_branch, merge_options) }
82
+
83
+ it 'checks out master as the default destination branch and squash merges the feature branch' do
84
+ expect { subject }.to have_run_commands_in_order [
85
+ 'git checkout master',
86
+ "git merge --squash #{feature_branch}"
87
+ ]
88
+ end
89
+
90
+ context "providing a destination branch" do
91
+ let(:merge_options) {{ destination_branch: destination_branch }}
92
+ it { expect{ subject }.to have_run_command "git checkout #{destination_branch}" }
93
+ end
94
+
95
+ context "with a message" do
96
+ let(:merge_options) {{ message: "don't throw doo doo" }}
97
+ it "appends the message to the squashed commit message" do
98
+ Gitacular.should_receive(:append_to_squashed_commit_message).with("don't throw doo doo")
99
+ subject
100
+ end
101
+
102
+ context 'and a pull reuqest number' do
103
+ before { merge_options.merge!(pull_request_number: 3) }
104
+ it "appends the message to the squashed commit message" do
105
+ Gitacular.should_receive(:append_to_squashed_commit_message).with("don't throw doo doo\nCloses #3\n")
106
+ subject
107
+ end
108
+ end
109
+ end
110
+
111
+ context "with a pull request number" do
112
+ let(:merge_options) {{ pull_request_number: 3 }}
113
+ it "appends the message to the squashed commit message" do
114
+ Gitacular.should_receive(:append_to_squashed_commit_message).with("\nCloses #3\n")
115
+ subject
116
+ end
117
+ end
118
+
119
+ context "with one LGTM author" do
120
+ let(:merge_options) {{ lgtm_authors: 'codenamev' }}
121
+ it "appends the message to the squashed commit message" do
122
+ Gitacular.should_receive(:append_to_squashed_commit_message).with("\nLGTM given by: @#{merge_options[:lgtm_authors]}\n")
123
+ subject
124
+ end
125
+ end
126
+
127
+ context "with LGTM authors" do
128
+ let(:merge_options) {{ lgtm_authors: ['codenamev', 'nhance'] }}
129
+ it "appends the message to the squashed commit message" do
130
+ Gitacular.should_receive(:append_to_squashed_commit_message).with("\nLGTM given by: @#{merge_options[:lgtm_authors].join(', @')}\n")
131
+ subject
132
+ end
133
+ end
134
+ end
135
+
136
+ describe ".append_to_squashed_commit_message(message)" do
137
+ let(:message) { "do do the voodoo that you do" }
138
+ subject { Gitacular.append_to_squashed_commit_message(message) }
139
+ it "appends the message to git's SQUASH_MSG temp file" do
140
+ expect{ subject }.to have_run_commands_in_order [
141
+ "echo \"#{message}\" | cat - .git/SQUASH_MSG > ./tmp_squash_msg",
142
+ 'mv ./tmp_squash_msg .git/SQUASH_MSG'
143
+ ]
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe GitReflow::GitServer do
4
+ let(:connection_options) { nil }
5
+
6
+ subject { GitReflow::GitServer.connect connection_options }
7
+
8
+ before do
9
+ GitReflow::GitServer::GitHub.stub(:new)
10
+
11
+ module GitReflow::GitServer
12
+ class DummyHub < Base
13
+ def initialize(options)
14
+ "Initialized with #{options}"
15
+ end
16
+
17
+ def authenticate(options={})
18
+ end
19
+
20
+ def connection
21
+ 'Connected!'
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ describe '.connect(options)' do
28
+ it 'initializes a new GitHub server provider by default' do
29
+ stubbed_github = Class.new
30
+ stubbed_github.stub(:authenticate)
31
+ GitReflow::GitServer::GitHub.should_receive(:new).and_return(stubbed_github)
32
+ subject
33
+ end
34
+
35
+ context 'provider is specified' do
36
+ let(:connection_options) { {provider: 'DummyHub'}.merge(expected_server_options) }
37
+ let(:expected_server_options) {{ basic_auth: 'user:pass', end_point: 'https://api.example.com' }}
38
+
39
+ it 'initializes any server provider that has been implemented' do
40
+ dummy_hub = GitReflow::GitServer::DummyHub.new({})
41
+ GitReflow::GitServer::DummyHub.should_receive(:new).with(expected_server_options).and_return(dummy_hub)
42
+ subject.should == dummy_hub
43
+ $output.should_not include 'GitServer not setup for: DummyHub'
44
+ end
45
+ end
46
+
47
+ context 'provider not yet implemented' do
48
+ let(:connection_options) {{ provider: 'GitLab' }}
49
+ it { expect{ subject }.to have_output "Error connecting to GitLab: GitServer not setup for \"GitLab\"" }
50
+ end
51
+ end
52
+
53
+ describe '.current_provider' do
54
+ subject { GitReflow::GitServer.current_provider }
55
+
56
+ context 'Reflow setup to use GitHub' do
57
+ before { GitReflow::Config.stub(:get).with('reflow.git-server').and_return('GitHub') }
58
+ it { should == GitReflow::GitServer::GitHub }
59
+ end
60
+
61
+ context 'Reflow has not yet been setup' do
62
+ before { GitReflow::Config.stub(:get).with('reflow.git-server').and_return('') }
63
+ it { should be_nil }
64
+ it { expect{ subject }.to have_output "[notice] Reflow hasn't been setup yet. Run 'git reflow setup' to continue" }
65
+ end
66
+
67
+ context 'an unknown server provider is stored in the git config' do
68
+ before { GitReflow::Config.stub(:get).with('reflow.git-server').and_return('GittyUp') }
69
+
70
+ it { should be_nil }
71
+ it { expect{ subject }.to have_output "GitServer not setup for \"GittyUp\"" }
72
+ end
73
+ end
74
+
75
+ describe '.connection' do
76
+ subject { GitReflow::GitServer.connection }
77
+
78
+ it { should be_nil }
79
+
80
+ context "with a valid provider" do
81
+ before { GitReflow::Config.stub(:get).with('reflow.git-server').and_return('GitHub') }
82
+ it 'calls connection on the provider' do
83
+ GitReflow::GitServer::GitHub.should_receive(:connection)
84
+ subject
85
+ end
86
+ end
87
+
88
+ context "with an invalid provider" do
89
+ before { GitReflow::Config.stub(:get).with('reflow.git-server').and_return('GittyUp') }
90
+ it { should be_nil }
91
+ it { expect{ subject }.to have_output "GitServer not setup for \"GittyUp\"" }
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,236 @@
1
+ require 'spec_helper'
2
+
3
+ describe GitReflow::GitServer::GitHub do
4
+ let(:user) { 'reenhanced' }
5
+ let(:password) { 'shazam' }
6
+ let(:repo) { 'repo' }
7
+ let(:oauth_token_hash) { Hashie::Mash.new({ token: 'a1b2c3d4e5f6g7h8i9j0'}) }
8
+ let(:hostname) { 'hostname.local' }
9
+ let(:github_site) { 'https://github.com' }
10
+ let(:github_api_endpoint) { 'https://api.github.com' }
11
+ let(:enterprise_site) { 'https://github.gittyup.com' }
12
+ let(:enterprise_api) { 'https://github.gittyup.com/api/v3' }
13
+ let(:github) { stub_github_with(pull: existing_pull_request) }
14
+ let!(:github_api) { github.connection }
15
+ let(:existing_pull_request) { Hashie::Mash.new JSON.parse(fixture('pull_requests/pull_request.json').read) }
16
+ let(:existing_pull_requests) { JSON.parse(fixture('pull_requests/pull_requests.json').read).collect {|pull| Hashie::Mash.new pull } }
17
+
18
+ before do
19
+ HighLine.any_instance.stub(:ask) do |terminal, question|
20
+ values = {
21
+ "Please enter your GitHub username: " => user,
22
+ "Please enter your GitHub password (we do NOT store this): " => password,
23
+ "Please enter your Enterprise site URL (e.g. https://github.company.com):" => enterprise_site,
24
+ "Please enter your Enterprise API endpoint (e.g. https://github.company.com/api/v3):" => enterprise_api
25
+ }
26
+ return_value = values[question]
27
+ question = ""
28
+ return_value
29
+ end
30
+
31
+ github.stub(:remote_user).and_return(user)
32
+ github.stub(:remote_repo_name).and_return(repo)
33
+ github.stub(:run).with('hostname', loud: false).and_return(hostname)
34
+ end
35
+
36
+ describe '#initialize(options)' do
37
+ subject { GitReflow::GitServer::GitHub.new({}) }
38
+
39
+ it 'sets the reflow git server provider to GitHub in the git config' do
40
+ GitReflow::Config.should_receive(:set).once.with('github.site', github_site, local: false)
41
+ GitReflow::Config.should_receive(:set).once.with('github.endpoint', github_api_endpoint, local: false)
42
+ GitReflow::Config.should_receive(:set).once.with('reflow.git-server', 'GitHub')
43
+ subject
44
+ end
45
+
46
+ context 'using enterprise' do
47
+ subject { GitReflow::GitServer::GitHub.new(enterprise: true) }
48
+
49
+ it 'sets the enterprise site and api as the site and api endpoints for the GitHub provider in the git config' do
50
+ GitReflow::Config.should_receive(:set).once.with('github.site', enterprise_site, local: false)
51
+ GitReflow::Config.should_receive(:set).once.with('github.endpoint', enterprise_api, local: false)
52
+ GitReflow::Config.should_receive(:set).once.with('reflow.git-server', 'GitHub')
53
+ subject
54
+ end
55
+
56
+ end
57
+
58
+ context 'storing git config settings only for this project' do
59
+ subject { GitReflow::GitServer::GitHub.new(project_only: true) }
60
+
61
+ it 'sets the enterprise site and api as the site and api endpoints for the GitHub provider in the git config' do
62
+ GitReflow::Config.should_receive(:set).once.with('github.site', github_site, local: true).and_call_original
63
+ GitReflow::Config.should_receive(:set).once.with('github.endpoint', github_api_endpoint, local: true)
64
+ GitReflow::Config.should_receive(:set).once.with('reflow.git-server', 'GitHub', local: true)
65
+ subject
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ describe '#authenticate' do
72
+ let(:github) { GitReflow::GitServer::GitHub.new({}) }
73
+ let!(:github_api) { Github.new }
74
+ let(:github_authorizations) { Github::Client::Authorizations.new }
75
+ subject { github.authenticate }
76
+
77
+ before do
78
+ GitReflow::GitServer::GitHub.stub(:user).and_return('reenhanced')
79
+ github_api.stub(:oauth).and_return(github_authorizations)
80
+ github_api.stub_chain(:oauth, :all).and_return([])
81
+ github.stub(:run).with('hostname', loud: false).and_return(hostname)
82
+ end
83
+
84
+ context 'not yet authenticated' do
85
+ context 'with valid GitHub credentials' do
86
+
87
+ before do
88
+ Github.stub(:new).and_return(github_api)
89
+ github_authorizations.stub(:authenticated?).and_return(true)
90
+ github_api.oauth.stub(:create).with({ scopes: ['repo'], note: "git-reflow (#{hostname})" }).and_return(oauth_token_hash)
91
+ end
92
+
93
+ it "notifies the user of successful setup" do
94
+ expect { subject }.to have_output "\nYour GitHub account was successfully setup!"
95
+ end
96
+
97
+ it "creates a new GitHub oauth token" do
98
+ github_api.oauth.should_receive(:create).and_return(oauth_token_hash)
99
+ subject
100
+ end
101
+
102
+ it "creates git config keys for github connections" do
103
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all github.site \"#{GitReflow::GitServer::GitHub.site_url}\""
104
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all github.endpoint \"#{GitReflow::GitServer::GitHub.api_endpoint}\""
105
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all github.oauth-token \"#{oauth_token_hash[:token]}\""
106
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all reflow.git-server \"GitHub\""
107
+ end
108
+
109
+ context "exclusive to project" do
110
+ let(:github) { GitReflow::GitServer::GitHub.new(project_only: true) }
111
+ before { GitReflow::GitServer::GitHub.stub(:@project_only).and_return(true) }
112
+
113
+ it "creates _local_ git config keys for github connections" do
114
+ expect{ subject }.to_not have_run_command_silently "git config --global --replace-all github.site \"#{GitReflow::GitServer::GitHub.site_url}\""
115
+ expect{ subject }.to_not have_run_command_silently "git config --global --replace-all github.endpoint \"#{GitReflow::GitServer::GitHub.api_endpoint}\""
116
+ expect{ subject }.to_not have_run_command_silently "git config --global --replace-all github.oauth-token \"#{oauth_token_hash[:token]}\""
117
+ expect{ subject }.to_not have_run_command_silently "git config --global --replace-all reflow.git-server \"GitHub\""
118
+
119
+ expect{ subject }.to have_run_command_silently "git config --replace-all github.site \"#{GitReflow::GitServer::GitHub.site_url}\""
120
+ expect{ subject }.to have_run_command_silently "git config --replace-all github.endpoint \"#{GitReflow::GitServer::GitHub.api_endpoint}\""
121
+ expect{ subject }.to have_run_command_silently "git config --replace-all github.oauth-token \"#{oauth_token_hash[:token]}\""
122
+ expect{ subject }.to have_run_command_silently "git config --replace-all reflow.git-server \"GitHub\""
123
+ end
124
+ end
125
+
126
+ context "use GitHub enterprise account" do
127
+ let(:github) { GitReflow::GitServer::GitHub.new(enterprise: true) }
128
+ before { GitReflow::GitServer::GitHub.stub(:@using_enterprise).and_return(true) }
129
+ it "creates git config keys for github connections" do
130
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all github.site \"#{enterprise_site}\""
131
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all github.endpoint \"#{enterprise_api}\""
132
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all github.oauth-token \"#{oauth_token_hash[:token]}\""
133
+ expect{ subject }.to have_run_command_silently "git config --global --replace-all reflow.git-server \"GitHub\""
134
+ end
135
+ end
136
+ end
137
+
138
+ context "with invalid GitHub credentials" do
139
+ let(:unauthorized_error_response) {{
140
+ response_headers: {'content-type' => 'application/json; charset=utf-8', status: 'Unauthorized'},
141
+ method: 'GET',
142
+ status: '401',
143
+ body: { error: "GET https://api.github.com/authorizations: 401 Bad credentials" }
144
+ }}
145
+
146
+ before do
147
+ Github.should_receive(:new).and_raise Github::Error::Unauthorized.new(unauthorized_error_response)
148
+ end
149
+
150
+ it "notifies user of invalid login details" do
151
+ expect { subject }.to have_output "\nInvalid username or password: #{Github::Error::Unauthorized.new(unauthorized_error_response).inspect}"
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ describe '#create_pull_request(options)' do
158
+ let(:title) { 'Fresh title' }
159
+ let(:body) { 'Funky body' }
160
+ let(:current_branch) { 'new-feature' }
161
+
162
+ before { github.stub(:current_branch).and_return(current_branch) }
163
+
164
+ it 'creates a pull request using the remote user and repo' do
165
+ github_api.stub(:pull_requests)
166
+ github_api.pull_requests.should_receive(:create).with(user, repo, title: title, body: body, head: "#{user}:#{current_branch}", base: 'master')
167
+ github.create_pull_request({ title: title, body: body, base: 'master' })
168
+ end
169
+ end
170
+
171
+ describe '#find_pull_request(from, to)' do
172
+ subject { github.find_pull_request({ from: 'new-feature', to: 'master'}) }
173
+
174
+ it 'looks for an open pull request matching the remote user/repo' do
175
+ subject.should == existing_pull_requests.first
176
+ end
177
+
178
+ context 'no pull request exists' do
179
+ before { github.stub(:find_pull_request).and_return([]) }
180
+ it { should == [] }
181
+ end
182
+ end
183
+
184
+ describe '#pull_request_comments(pull_request)' do
185
+ let(:pull_request_comments) { JSON.parse(fixture('pull_requests/comments.json').read).collect {|c| Hashie::Mash.new(c) } }
186
+
187
+ subject { github.pull_request_comments(existing_pull_request) }
188
+
189
+ before do
190
+ github_api.stub_chain(:issues, :comments)
191
+ github_api.stub_chain(:pull_requests, :comments)
192
+ end
193
+
194
+ it 'includes both issue comments and pull request comments' do
195
+ github_api.issues.comments.should_receive(:all).with(user, repo, number: existing_pull_request.number).and_return([pull_request_comments.first])
196
+ github_api.pull_requests.comments.should_receive(:all).with(user, repo, number: existing_pull_request.number).and_return([pull_request_comments.first])
197
+ subject.count.should == 2
198
+ end
199
+ end
200
+
201
+ describe '#has_pull_request_comments?(pull_request)' do
202
+ let(:existing_pull_request) { Hashie::Mash.new JSON.parse(fixture('pull_requests/pull_request.json').read) }
203
+ let(:pull_request_comments) { JSON.parse(fixture('pull_requests/comments.json').read).collect {|c| Hashie::Mash.new(c) } }
204
+
205
+ before { github.stub(:pull_request_comments).and_return([pull_request_comments]) }
206
+ subject { github.has_pull_request_comments?(existing_pull_request) }
207
+
208
+ it { should == true }
209
+
210
+ context 'no comments exist for the given pull request' do
211
+ before { github.stub(:pull_request_comments).and_return([]) }
212
+ it { should == false }
213
+ end
214
+ end
215
+
216
+ describe '#get_build_status(sha)' do
217
+ let(:sha) { '6dcb09b5b57875f334f61aebed695e2e4193db5e' }
218
+ subject { github.get_build_status(sha) }
219
+ before { github_api.stub_chain(:repos, :statuses) }
220
+
221
+ it 'gets the latest build status for the given commit hash' do
222
+ github_api.repos.statuses.should_receive(:all).with(user, repo, sha).and_return([{ state: 'success'}])
223
+ subject
224
+ end
225
+ end
226
+
227
+ describe '#find_authors_of_open_pull_request_comments(pull_request)' do
228
+ end
229
+
230
+ describe '#comment_authors_for_pull_request(pull_request, options = {})' do
231
+ end
232
+
233
+ describe '#get_commited_time(commit_sha)' do
234
+ end
235
+
236
+ end
@@ -0,0 +1,37 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'multi_json'
4
+ require 'webmock/rspec'
5
+ require 'pry'
6
+
7
+ $LOAD_PATH << 'lib'
8
+ require 'git_reflow'
9
+
10
+ Dir[File.expand_path('../support/**/*.rb', __FILE__)].each {|f| require f}
11
+
12
+ RSpec.configure do |config|
13
+ config.include GithubHelpers
14
+ config.include WebMock::API
15
+ config.include CommandLineHelpers
16
+ config.include GithubHelpers
17
+ config.include RspecStubHelpers
18
+
19
+ config.expect_with :rspec do |c|
20
+ c.syntax = [:should, :expect]
21
+ end
22
+
23
+ config.mock_with :rspec do |c|
24
+ c.syntax = [:should, :expect]
25
+ end
26
+
27
+ config.before(:each) do
28
+ WebMock.reset!
29
+ stub_command_line
30
+ allow_message_expectations_on_nil
31
+ end
32
+
33
+ config.after(:each) do
34
+ WebMock.reset!
35
+ reset_stubbed_command_line
36
+ end
37
+ end
@@ -0,0 +1,99 @@
1
+ module CommandLineHelpers
2
+ def stub_command_line
3
+ $commands_ran = []
4
+ $output = []
5
+
6
+ stub_run_for GitReflow
7
+ stub_run_for GitReflow::Sandbox
8
+
9
+ STDOUT.stub(:puts) do |output|
10
+ $output << output
11
+ output = ''
12
+ end
13
+ end
14
+
15
+ def stub_run_for(module_to_stub)
16
+ module_to_stub.stub(:run) do |command, options|
17
+ options ||= {}
18
+ $commands_ran << Hashie::Mash.new(command: command, options: options)
19
+ command = "" # we need this due to a bug in rspec that will keep this assignment on subsequent runs of the stub
20
+ end
21
+ end
22
+
23
+ def reset_stubbed_command_line
24
+ $commands_ran = []
25
+ end
26
+
27
+ def stub_command(command, return_value)
28
+ GitReflow::Sandbox.stub(:run).with(command).and_return(return_value)
29
+ end
30
+ end
31
+
32
+ RSpec::Matchers.define :have_run_command do |command|
33
+ match do |block|
34
+ block.call
35
+ (
36
+ $commands_ran.include? Hashie::Mash.new(command: command, options: {}) or
37
+ $commands_ran.include? Hashie::Mash.new(command: command, options: {with_system: true})
38
+ )
39
+ end
40
+
41
+ supports_block_expectations
42
+
43
+ failure_message do |block|
44
+ "expected to have run the command \`#{command}\` but instead ran:\n\t#{$commands_ran.inspect}"
45
+ end
46
+ end
47
+
48
+ RSpec::Matchers.define :have_run_command_silently do |command|
49
+ match do |block|
50
+ block.call
51
+ $commands_ran.include? Hashie::Mash.new(command: command, options: { loud: false })
52
+ end
53
+
54
+ supports_block_expectations
55
+
56
+ failure_message do |block|
57
+ "expected to have run the command \`#{command}\` silently but instead ran:\n\t#{$commands_ran.inspect}"
58
+ end
59
+ end
60
+
61
+ RSpec::Matchers.define :have_run_commands_in_order do |commands|
62
+ match do |block|
63
+ block.call
64
+ command_count = commands.count
65
+ command_start_index = $commands_ran.reverse.find_index {|c| c.command == commands.first }
66
+ return false unless command_start_index
67
+
68
+ $commands_ran.reverse.each_with_index do |command_ran, index|
69
+ next unless command_start_index
70
+ if command_count >= 1
71
+ current_command = commands[command_count - 1]
72
+ current_command.should == command_ran.command
73
+ command_count -= 1
74
+ end
75
+ end
76
+
77
+ return command_count == 0
78
+ end
79
+
80
+ supports_block_expectations
81
+
82
+ failure_message do |block|
83
+ "expected to have run these commands in order:\n\t\t#{commands.inspect}\n\tgot:\n\t\t#{$commands_ran.inspect}"
84
+ end
85
+ end
86
+
87
+ RSpec::Matchers.define :have_output do |expected_output|
88
+ match do |block|
89
+ block.call
90
+ $output.include? expected_output
91
+ end
92
+
93
+ supports_block_expectations
94
+
95
+ failure_message do |block|
96
+ "expected STDOUT to include #{expected_output} but didn't: \n\t#{$output.inspect}"
97
+ end
98
+ end
99
+
@@ -0,0 +1,8 @@
1
+ def fixture_path
2
+ File.expand_path("../../fixtures", __FILE__)
3
+ end
4
+
5
+ def fixture(file)
6
+ File.new(File.join(fixture_path, '/', file))
7
+ end
8
+