socialcast-git-extensions 3.1.15 → 3.1.17

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b008a4a9b2357de82f9e62a7fa5ef31fd9e705b3
4
+ data.tar.gz: b30af5a791a45d3283cc79c54ff34ca2dc5fdd88
5
+ SHA512:
6
+ metadata.gz: 9eac64d626bf695194df42d14631f7d192d1b8524571916edecdb45b7a0c245097664e65d055c9f4b39779ec885731472b63b1479c181c57fb8af03777d9bf89
7
+ data.tar.gz: 80a3e05443dc8a8264754411d32b604b37338f0294674b4e69d3096313cd628cc36889c07bcecea5aa5106f1d9f32a1bf1f43236687fadfe30721b08df061c6f
data/README.md CHANGED
@@ -86,4 +86,5 @@ reset an aggregate branch (ex: prototype, staging) back to a known good state.
86
86
 
87
87
  ## Copyright
88
88
 
89
- Copyright (c) 2010 Socialcast, Inc. See LICENSE for details.
89
+ Copyright (c) 2014 Socialcast, Inc. See LICENSE for details.
90
+
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'socialcast-git-extensions', 'cli.rb')
4
+ Socialcast::Gitx::CLI.start (['backportpr'] + ARGV)
@@ -8,6 +8,7 @@ module Socialcast
8
8
  module Gitx
9
9
  DEFAULT_BASE_BRANCH = 'master'
10
10
  DEFAULT_STAGING_BRANCH = 'staging'
11
+ DEFAULT_LAST_KNOWN_GOOD_STAGING_BRANCH = 'last_known_good_staging'
11
12
  DEFAULT_PROTOTYPE_BRANCH = 'prototype'
12
13
 
13
14
  private
@@ -33,8 +33,6 @@ module Socialcast
33
33
  method_option :skip_additional_reviewers, :type => :string, :aliases => '-s', :desc => 'Skips adding additional reviewers'
34
34
  # @see http://developer.github.com/v3/pulls/
35
35
  def reviewrequest(*additional_reviewers)
36
- token = authorization_token
37
-
38
36
  update
39
37
 
40
38
  review_mention = if buddy = socialcast_review_buddy(current_user)
@@ -63,7 +61,7 @@ module Socialcast
63
61
  description = options[:description] || editor_input(PULL_REQUEST_DESCRIPTION)
64
62
  branch = current_branch
65
63
  repo = current_repo
66
- url = create_pull_request token, branch, repo, description, assignee
64
+ url = create_pull_request branch, repo, description, assignee
67
65
  say "Pull request created: #{url}"
68
66
 
69
67
  short_description = description.split("\n").first(5).join("\n")
@@ -73,9 +71,8 @@ module Socialcast
73
71
 
74
72
  desc "findpr", "Find pull requests including a given commit"
75
73
  def findpr(commit_hash)
76
- token = authorization_token
77
74
  repo = current_repo
78
- data = pull_requests_for_commit(token, repo, commit_hash)
75
+ data = pull_requests_for_commit(repo, commit_hash)
79
76
 
80
77
  if data['items']
81
78
  data['items'].each do |entry|
@@ -84,7 +81,38 @@ module Socialcast
84
81
  else
85
82
  say "No results found", :yellow
86
83
  end
84
+ end
85
+
86
+ desc "backportpr", "Backport a pull request"
87
+ def backportpr(pull_request_num, maintenance_branch)
88
+ original_base_branch = ENV['BASE_BRANCH']
89
+ ENV['BASE_BRANCH'] = maintenance_branch
90
+ repo = current_repo
91
+ assignee = github_track_reviewer('Backport')
92
+ socialcast_reviewer = socialcast_track_reviewer('Backport')
93
+
94
+ pull_request_data = github_api_request('GET', "repos/#{repo}/pulls/#{pull_request_num}")
95
+ commits_data = github_api_request('GET', pull_request_data['commits_url'])
87
96
 
97
+ non_merge_commits_data = commits_data.select { |commit_data| commit_data['parents'].length == 1 }
98
+ shas = non_merge_commits_data.map { |commit| commit['sha'] }
99
+
100
+ backport_branch = "backport_#{pull_request_num}_to_#{maintenance_branch}"
101
+ backport_to(backport_branch, shas)
102
+
103
+ maintenance_branch_url = "https://github.com/#{repo}/tree/#{maintenance_branch}"
104
+ description = "Backport ##{pull_request_num} to #{maintenance_branch_url}\n***\n#{pull_request_data['body']}"
105
+
106
+ pull_request_url = create_pull_request(backport_branch, repo, description, assignee)
107
+
108
+ review_message = ["#reviewrequest backport ##{pull_request_num} to #{maintenance_branch} #scgitx"]
109
+ if socialcast_reviewer
110
+ review_message << "/cc @#{socialcast_reviewer} for #backport track"
111
+ end
112
+ review_message << "/cc @SocialcastDevelopers"
113
+ post review_message.join("\n\n"), :url => pull_request_url, :message_type => 'review_request'
114
+ ensure
115
+ ENV['BASE_BRANCH'] = original_base_branch
88
116
  end
89
117
 
90
118
  # TODO: use --no-edit to skip merge messages
@@ -193,6 +221,7 @@ module Socialcast
193
221
  def release
194
222
  branch = current_branch
195
223
  assert_not_protected_branch!(branch, 'release')
224
+ assert_in_last_known_good_staging(branch)
196
225
 
197
226
  return unless yes?("Release #{branch} to production? (y/n)", :green)
198
227
 
@@ -9,6 +9,13 @@ module Socialcast
9
9
  raise "Cannot #{action} reserved branch" if reserved_branch?(branch)
10
10
  end
11
11
 
12
+ def assert_in_last_known_good_staging(branch)
13
+ branches_in_last_known_staging = branches(:remote => true, :merged => last_known_good_staging_branch)
14
+ unless branches_in_last_known_staging.include? branch
15
+ raise "Cannot release #{branch} unless it has already been promoted separately to #{staging_branch} and the build has passed."
16
+ end
17
+ end
18
+
12
19
  # lookup the current branch of the PWD
13
20
  def current_branch
14
21
  repo = Grit::Repo.new(Dir.pwd)
@@ -28,6 +35,27 @@ module Socialcast
28
35
  `git config -z --global --get github.user`.strip
29
36
  end
30
37
 
38
+ def backport_to(branch, shas)
39
+ run_cmd "git checkout #{base_branch}"
40
+ run_cmd "git checkout -b #{branch}"
41
+ begin
42
+ run_cmd "git cherry-pick #{shas.join(' ')}"
43
+ rescue
44
+ while true
45
+ proceed = $terminal.ask "Error during cherry-pick. You can proceed by resolving the conflicts and using 'git cherry-pick --continue' to finish the cherry-pick in another terminal. Would you like to proceed (y/n)?"
46
+ if proceed.to_s.downcase == 'n'
47
+ run_cmd "git cherry-pick --abort"
48
+ exit 1
49
+ elsif proceed.to_s.downcase == 'y'
50
+ break
51
+ else
52
+ say "Invalid response"
53
+ end
54
+ end
55
+ end
56
+ run_cmd "git push origin HEAD"
57
+ end
58
+
31
59
  # retrieve a list of branches
32
60
  def branches(options = {})
33
61
  branches = []
@@ -185,6 +213,10 @@ module Socialcast
185
213
  config['staging_branch'] || Socialcast::Gitx::DEFAULT_STAGING_BRANCH
186
214
  end
187
215
 
216
+ def last_known_good_staging_branch
217
+ config['last_known_good_staging_branch'] || Socialcast::Gitx::DEFAULT_LAST_KNOWN_GOOD_STAGING_BRANCH
218
+ end
219
+
188
220
  def prototype_branch
189
221
  config['prototype_branch'] || Socialcast::Gitx::DEFAULT_PROTOTYPE_BRANCH
190
222
  end
@@ -32,7 +32,7 @@ module Socialcast
32
32
 
33
33
  # returns the url of the created pull request
34
34
  # @see http://developer.github.com/v3/pulls/
35
- def create_pull_request(token, branch, repo, body, assignee)
35
+ def create_pull_request(branch, repo, body, assignee)
36
36
  payload = {:title => branch, :base => base_branch, :head => branch, :body => body}.to_json
37
37
  say "Creating pull request for "
38
38
  say "#{branch} ", :green
@@ -40,41 +40,26 @@ module Socialcast
40
40
  say "#{base_branch} ", :green
41
41
  say "in "
42
42
  say repo, :green
43
- response = RestClient::Request.new(:url => "https://api.github.com/repos/#{repo}/pulls", :method => "POST", :payload => payload, :headers => {:accept => :json, :content_type => :json, 'Authorization' => "token #{token}"}).execute
44
- data = JSON.parse response.body
45
-
46
- assign_pull_request(token, branch, assignee, data) if assignee ## Unfortunately this needs to be done in a seperate request.
43
+ data = github_api_request("POST", "repos/#{repo}/pulls", payload)
44
+ assign_pull_request(branch, assignee, data) if assignee ## Unfortunately this needs to be done in a seperate request.
47
45
 
48
46
  url = data['html_url']
49
47
  url
50
- rescue RestClient::Exception => e
51
- process_error e
52
- throw e
53
48
  end
54
49
 
55
50
  # find the PRs matching the given commit hash
56
51
  # https://developer.github.com/v3/search/#search-issues
57
- def pull_requests_for_commit(token, repo, commit_hash)
52
+ def pull_requests_for_commit(repo, commit_hash)
58
53
  query = "#{commit_hash}+type:pr+repo:#{repo}"
59
54
  say "Searching github pull requests for #{commit_hash}"
60
- response = RestClient::Request.new(:url => "https://api.github.com/search/issues?q=#{query}", :method => "GET", :headers => {:accept => :json, :content_type => :json, 'Authorization' => "token #{token}"}).execute
61
- JSON.parse response.body
62
- rescue RestClient::Exception => e
63
- process_error e
64
- throw e
55
+ github_api_request "GET", "search/issues?q=#{query}"
65
56
  end
66
57
 
67
- def assign_pull_request(token, branch, assignee, data)
58
+ def assign_pull_request(branch, assignee, data)
68
59
  issue_payload = { :title => branch, :assignee => assignee }.to_json
69
- RestClient::Request.new(:url => data['issue_url'], :method => "PATCH", :payload => issue_payload, :headers => {:accept => :json, :content_type => :json, 'Authorization' => "token #{token}"}).execute
70
- rescue RestClient::Exception => e
71
- data = JSON.parse e.http_body
72
- say "Failed to assign pull request: #{data['message']}", :red
73
- end
74
-
75
- def process_error(e)
76
- data = JSON.parse e.http_body
77
- say "Failed to create pull request: #{data['message']}", :red
60
+ github_api_request "PATCH", data['issue_url'], issue_payload
61
+ rescue => e
62
+ say "Failed to assign pull request: #{e.message}", :red
78
63
  end
79
64
 
80
65
  # @returns [String] socialcast username to assign the review to
@@ -94,6 +79,43 @@ module Socialcast
94
79
  end
95
80
  end
96
81
 
82
+ # @returns [String] github username responsible for the track
83
+ # @returns [nil] when user not found
84
+ def github_track_reviewer(track)
85
+ github_username_for_socialcast_username(socialcast_track_reviewer(track))
86
+ end
87
+
88
+ # @returns [String] Socialcast username responsible for the track
89
+ # @returns [nil] when user not found
90
+ def socialcast_track_reviewer(track)
91
+ specialty_reviewers.values.each do |reviewer_hash|
92
+ return reviewer_hash['socialcast_username'] if reviewer_hash['label'].to_s.downcase == track.downcase
93
+ end
94
+ nil
95
+ end
96
+
97
+ # @returns [String] github username corresponding to the Socialcast username
98
+ # @returns [nil] when user not found
99
+ def github_username_for_socialcast_username(socialcast_username)
100
+ return if socialcast_username.nil? || socialcast_username == ""
101
+
102
+ review_buddies.each_pair do |github_username, review_buddy_hash|
103
+ return github_username if review_buddy_hash['socialcast_username'] == socialcast_username
104
+ end
105
+ end
106
+
107
+ def github_api_request(method, path, payload = nil)
108
+ url = path.include?('http') ? path : "https://api.github.com/#{path}"
109
+ JSON.parse RestClient::Request.new(:url => url, :method => method, :payload => payload, :headers => { :accept => :json, :content_type => :json, 'Authorization' => "token #{authorization_token}", :user_agent => 'socialcast-git-extensions' }).execute
110
+ rescue RestClient::Exception => e
111
+ process_error e
112
+ throw e
113
+ end
114
+
115
+ def process_error(e)
116
+ data = JSON.parse e.http_body
117
+ say "GitHub request failed: #{data['message']}", :red
118
+ end
97
119
  end
98
120
  end
99
121
  end
@@ -1,5 +1,5 @@
1
1
  module Socialcast
2
2
  module Gitx
3
- VERSION = "3.1.15"
3
+ VERSION = "3.1.17"
4
4
  end
5
5
  end
@@ -14,15 +14,14 @@ Gem::Specification.new do |s|
14
14
 
15
15
  s.rubyforge_project = "socialcast-git-extensions"
16
16
 
17
- s.add_dependency(%q<json_pure>, [">= 0"])
18
- s.add_runtime_dependency(%q<grit>, [">= 0"])
19
- s.add_runtime_dependency(%q<socialcast>, [">= 1.3.0"])
20
- s.add_runtime_dependency(%q<rest-client>, [">= 1.4.0"])
21
- s.add_runtime_dependency(%q<thor>, [">= 0"])
22
- s.add_development_dependency(%q<rake>, ["0.9.2.2"])
23
- s.add_development_dependency "rspec", '>= 2.11.0'
24
- s.add_development_dependency "pry", '>= 0'
25
- s.add_development_dependency "webmock", '>= 0'
17
+ s.add_runtime_dependency 'grit', '~> 2.5.0'
18
+ s.add_runtime_dependency 'socialcast', '~> 1.3.0'
19
+ s.add_runtime_dependency 'rest-client', '~> 1.6.7'
20
+ s.add_runtime_dependency 'thor', '~> 0.19.1'
21
+ s.add_runtime_dependency 'rake', '~> 10.3.2'
22
+ s.add_development_dependency 'rspec', '~> 3.0.0'
23
+ s.add_development_dependency 'pry', '~> 0.9.12.6'
24
+ s.add_development_dependency 'webmock', '~> 1.18.0'
26
25
 
27
26
  s.files = `git ls-files`.split("\n")
28
27
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
data/spec/cli_spec.rb CHANGED
@@ -14,10 +14,10 @@ describe Socialcast::Gitx::CLI do
14
14
  end
15
15
 
16
16
  def stub_message(message_body, params = {})
17
- json_body = { :message => { :body => message_body }.merge!(params) }
17
+ json_body = { :message => params.merge!(:body => message_body) }
18
18
 
19
19
  stub_request(:post, "https://testuser:testpassword@testdomain/api/messages.json")
20
- .with(:body => json_body)
20
+ .with(:body => json_body.to_json)
21
21
  .to_return(:status => 200, :body => '', :headers => {})
22
22
  end
23
23
 
@@ -27,23 +27,23 @@ describe Socialcast::Gitx::CLI do
27
27
  end
28
28
 
29
29
  Socialcast::Gitx::CLI.stubbed_executed_commands = []
30
- Socialcast::Gitx::CLI.any_instance.stub(:current_branch).and_return('FOO')
31
- Socialcast::Gitx::CLI.any_instance.stub(:current_user).and_return('wireframe')
32
- Socialcast::CommandLine.stub(:credentials).and_return(:domain => 'testdomain', :user => 'testuser', :password => 'testpassword', :scgitx_token => 'faketoken')
30
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:current_branch).and_return('FOO')
31
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:current_user).and_return('wireframe')
32
+ allow(Socialcast::CommandLine).to receive(:credentials).and_return(:domain => 'testdomain', :user => 'testuser', :password => 'testpassword', :scgitx_token => 'faketoken')
33
33
  end
34
34
 
35
35
  describe '#update' do
36
36
  before do
37
- Socialcast::Gitx::CLI.any_instance.should_not_receive(:post)
37
+ expect_any_instance_of(Socialcast::Gitx::CLI).not_to receive(:post)
38
38
  Socialcast::Gitx::CLI.start ['update']
39
39
  end
40
40
  it 'should not post message to socialcast' do end # see expectations
41
41
  it 'should run expected commands' do
42
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
42
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
43
43
  'git pull origin FOO',
44
44
  'git pull origin master',
45
45
  'git push origin HEAD'
46
- ]
46
+ ])
47
47
  end
48
48
  end
49
49
 
@@ -56,7 +56,7 @@ describe Socialcast::Gitx::CLI do
56
56
  end
57
57
  it 'should post message to socialcast' do end # see expectations
58
58
  it 'should default to prototype' do
59
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
59
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
60
60
  "git pull origin FOO",
61
61
  "git pull origin master",
62
62
  "git push origin HEAD",
@@ -67,12 +67,12 @@ describe Socialcast::Gitx::CLI do
67
67
  "git push origin HEAD",
68
68
  "git checkout FOO",
69
69
  "git checkout FOO"
70
- ]
70
+ ])
71
71
  end
72
72
  end
73
73
  context 'when target branch is ommitted with custom prototype branch' do
74
74
  before do
75
- Socialcast::Gitx::CLI.any_instance.stub(:prototype_branch).and_return('special-prototype')
75
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:prototype_branch).and_return('special-prototype')
76
76
 
77
77
  stub_message "#worklog integrating FOO into special-prototype #scgitx"
78
78
 
@@ -80,7 +80,7 @@ describe Socialcast::Gitx::CLI do
80
80
  end
81
81
  it 'should post message to socialcast' do end # see expectations
82
82
  it 'should default to prototype' do
83
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
83
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
84
84
  "git pull origin FOO",
85
85
  "git pull origin master",
86
86
  "git push origin HEAD",
@@ -91,7 +91,7 @@ describe Socialcast::Gitx::CLI do
91
91
  "git push origin HEAD",
92
92
  "git checkout FOO",
93
93
  "git checkout FOO"
94
- ]
94
+ ])
95
95
  end
96
96
  end
97
97
  context 'when target branch == prototype' do
@@ -102,7 +102,7 @@ describe Socialcast::Gitx::CLI do
102
102
  end
103
103
  it 'should post message to socialcast' do end # see expectations
104
104
  it 'should run expected commands' do
105
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
105
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
106
106
  "git pull origin FOO",
107
107
  "git pull origin master",
108
108
  "git push origin HEAD",
@@ -113,7 +113,7 @@ describe Socialcast::Gitx::CLI do
113
113
  "git push origin HEAD",
114
114
  "git checkout FOO",
115
115
  "git checkout FOO"
116
- ]
116
+ ])
117
117
  end
118
118
  end
119
119
  context 'when target branch == staging' do
@@ -124,7 +124,7 @@ describe Socialcast::Gitx::CLI do
124
124
  end
125
125
  it 'should post message to socialcast' do end # see expectations
126
126
  it 'should also integrate into prototype and run expected commands' do
127
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
127
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
128
128
  "git pull origin FOO",
129
129
  "git pull origin master",
130
130
  "git push origin HEAD",
@@ -141,39 +141,44 @@ describe Socialcast::Gitx::CLI do
141
141
  "git push origin HEAD",
142
142
  "git checkout staging",
143
143
  "git checkout FOO"
144
- ]
144
+ ])
145
145
  end
146
146
  end
147
147
  context 'when target branch != staging || prototype' do
148
148
  it 'should raise an error' do
149
- lambda {
149
+ expect {
150
150
  Socialcast::Gitx::CLI.start ['integrate', 'asdfasdfasdf']
151
- }.should raise_error(/Only aggregate branches are allowed for integration/)
151
+ }.to raise_error(/Only aggregate branches are allowed for integration/)
152
152
  end
153
153
  end
154
154
  end
155
155
 
156
156
  describe '#release' do
157
+ let(:branches_in_last_known_good_staging) { ['FOO'] }
158
+ before do
159
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:branches).with(:remote => true, :merged => 'last_known_good_staging').and_return(branches_in_last_known_good_staging)
160
+ end
161
+
157
162
  context 'when user rejects release' do
158
163
  before do
159
- Socialcast::Gitx::CLI.any_instance.should_receive(:yes?).and_return(false)
164
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:yes?).and_return(false)
160
165
  Socialcast::Gitx::CLI.start ['release']
161
166
  end
162
167
  it 'should run no commands' do
163
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == []
168
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([])
164
169
  end
165
170
  end
166
171
  context 'when user confirms release' do
167
172
  before do
168
173
  stub_message "#worklog releasing FOO to master #scgitx"
169
174
 
170
- Socialcast::Gitx::CLI.any_instance.should_receive(:yes?).and_return(true)
171
- Socialcast::Gitx::CLI.any_instance.should_receive(:cleanup)
175
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:yes?).and_return(true)
176
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:cleanup)
172
177
  Socialcast::Gitx::CLI.start ['release']
173
178
  end
174
179
  it 'should post message to socialcast' do end # see expectations
175
180
  it 'should run expected commands' do
176
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
181
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
177
182
  "git pull origin FOO",
178
183
  "git pull origin master",
179
184
  "git push origin HEAD",
@@ -187,20 +192,31 @@ describe Socialcast::Gitx::CLI do
187
192
  "git pull . master",
188
193
  "git push origin HEAD",
189
194
  "git checkout master"
190
- ]
195
+ ])
196
+ end
197
+ end
198
+
199
+ context 'when the branch is not in last_known_good_staging' do
200
+ let(:branches_in_last_known_good_staging) { ['another-branch'] }
201
+ before do
202
+ expect_any_instance_of(Socialcast::Gitx::CLI).not_to receive(:yes?)
203
+ end
204
+ it 'prevents the release of the branch' do
205
+ expect { Socialcast::Gitx::CLI.start ['release'] }.to raise_error(RuntimeError, 'Cannot release FOO unless it has already been promoted separately to staging and the build has passed.')
191
206
  end
192
207
  end
193
208
 
194
209
  context 'with reserved_branches via config file' do
195
210
  before do
196
211
  stub_message "#worklog releasing FOO to master #scgitx"
197
- Socialcast::Gitx::CLI.any_instance.should_receive(:yes?).and_return(true)
198
- Socialcast::Gitx::CLI.any_instance.stub(:config).and_return( { 'reserved_branches' => ['dont-del-me','dont-del-me-2'] })
212
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:yes?).and_return(true)
213
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:config).and_return( { 'reserved_branches' => ['dont-del-me','dont-del-me-2'] })
214
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:cleanup)
199
215
  Socialcast::Gitx::CLI.start ['release']
200
216
  end
201
217
  it "treats the alternative base branch as reserved" do
202
- Socialcast::Gitx::CLI.new.send(:reserved_branches).should include 'dont-del-me'
203
- Socialcast::Gitx::CLI.new.send(:reserved_branches).should include 'dont-del-me-2'
218
+ expect(Socialcast::Gitx::CLI.new.send(:reserved_branches)).to include 'dont-del-me'
219
+ expect(Socialcast::Gitx::CLI.new.send(:reserved_branches)).to include 'dont-del-me-2'
204
220
  end
205
221
  end
206
222
 
@@ -208,17 +224,17 @@ describe Socialcast::Gitx::CLI do
208
224
  before do
209
225
  stub_message "#worklog releasing FOO to special-master #scgitx"
210
226
 
211
- Socialcast::Gitx::CLI.any_instance.should_receive(:yes?).and_return(true)
212
- Socialcast::Gitx::CLI.any_instance.stub(:config).and_return( { 'base_branch' => 'special-master' })
213
- Socialcast::Gitx::CLI.any_instance.should_receive(:cleanup)
227
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:yes?).and_return(true)
228
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:config).and_return( { 'base_branch' => 'special-master' })
229
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:cleanup)
214
230
  Socialcast::Gitx::CLI.start ['release']
215
231
  end
216
232
  it 'should post message to socialcast' do end # see expectations
217
233
  it "treats the alternative base branch as reserved" do
218
- Socialcast::Gitx::CLI.new.send(:reserved_branches).should include 'special-master'
234
+ expect(Socialcast::Gitx::CLI.new.send(:reserved_branches)).to include 'special-master'
219
235
  end
220
236
  it 'should run expected commands' do
221
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
237
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
222
238
  "git pull origin FOO",
223
239
  "git pull origin special-master",
224
240
  "git push origin HEAD",
@@ -232,7 +248,7 @@ describe Socialcast::Gitx::CLI do
232
248
  "git pull . special-master",
233
249
  "git push origin HEAD",
234
250
  "git checkout special-master"
235
- ]
251
+ ])
236
252
  end
237
253
  end
238
254
 
@@ -240,9 +256,9 @@ describe Socialcast::Gitx::CLI do
240
256
  before do
241
257
  stub_message "#worklog releasing FOO to special-master #scgitx"
242
258
 
243
- Socialcast::Gitx::CLI.any_instance.should_receive(:yes?).and_return(true)
244
- Socialcast::Gitx::CLI.any_instance.stub(:config).and_return({})
245
- Socialcast::Gitx::CLI.any_instance.should_receive(:cleanup)
259
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:yes?).and_return(true)
260
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:config).and_return({})
261
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:cleanup)
246
262
  ENV['BASE_BRANCH'] = 'special-master'
247
263
  Socialcast::Gitx::CLI.start ['release']
248
264
  end
@@ -250,11 +266,11 @@ describe Socialcast::Gitx::CLI do
250
266
  ENV.delete('BASE_BRANCH')
251
267
  end
252
268
  it "treats the alternative base branch as reserved" do
253
- Socialcast::Gitx::CLI.new.send(:reserved_branches).should include 'special-master'
269
+ expect(Socialcast::Gitx::CLI.new.send(:reserved_branches)).to include 'special-master'
254
270
  end
255
271
  it 'should post message to socialcast' do end # see expectations
256
272
  it 'should run expected commands' do
257
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
273
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
258
274
  "git pull origin FOO",
259
275
  "git pull origin special-master",
260
276
  "git push origin HEAD",
@@ -268,7 +284,7 @@ describe Socialcast::Gitx::CLI do
268
284
  "git pull . special-master",
269
285
  "git push origin HEAD",
270
286
  "git checkout special-master"
271
- ]
287
+ ])
272
288
  end
273
289
  end
274
290
 
@@ -276,9 +292,9 @@ describe Socialcast::Gitx::CLI do
276
292
  before do
277
293
  stub_message "#worklog releasing FOO to special-master #scgitx"
278
294
 
279
- Socialcast::Gitx::CLI.any_instance.should_receive(:yes?).and_return(true)
280
- Socialcast::Gitx::CLI.any_instance.stub(:config).and_return({ 'base_branch' => 'extra-special-master' })
281
- Socialcast::Gitx::CLI.any_instance.should_receive(:cleanup)
295
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:yes?).and_return(true)
296
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:config).and_return({ 'base_branch' => 'extra-special-master' })
297
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:cleanup)
282
298
  ENV['BASE_BRANCH'] = 'special-master'
283
299
  Socialcast::Gitx::CLI.start ['release']
284
300
  end
@@ -286,12 +302,12 @@ describe Socialcast::Gitx::CLI do
286
302
  ENV.delete('BASE_BRANCH')
287
303
  end
288
304
  it "treats the alternative base branch as reserved" do
289
- Socialcast::Gitx::CLI.new.send(:reserved_branches).should include 'special-master'
290
- Socialcast::Gitx::CLI.new.send(:reserved_branches).should include 'extra-special-master'
305
+ expect(Socialcast::Gitx::CLI.new.send(:reserved_branches)).to include 'special-master'
306
+ expect(Socialcast::Gitx::CLI.new.send(:reserved_branches)).to include 'extra-special-master'
291
307
  end
292
308
  it 'should post message to socialcast' do end # see expectations
293
309
  it 'should run expected commands' do
294
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
310
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
295
311
  "git pull origin FOO",
296
312
  "git pull origin special-master",
297
313
  "git push origin HEAD",
@@ -305,7 +321,7 @@ describe Socialcast::Gitx::CLI do
305
321
  "git pull . special-master",
306
322
  "git push origin HEAD",
307
323
  "git checkout special-master"
308
- ]
324
+ ])
309
325
  end
310
326
  end
311
327
  end
@@ -315,13 +331,13 @@ describe Socialcast::Gitx::CLI do
315
331
  before do
316
332
  prototype_branches = %w( dev-foo dev-bar )
317
333
  master_branches = %w( dev-foo )
318
- Socialcast::Gitx::CLI.any_instance.should_receive(:branches).and_return(prototype_branches, master_branches, prototype_branches, master_branches)
334
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:branches).and_return(prototype_branches, master_branches, prototype_branches, master_branches)
319
335
  stub_message "#worklog resetting prototype branch to last_known_good_master #scgitx\n/cc @SocialcastDevelopers\n\nthe following branches were affected:\n* dev-bar"
320
336
  Socialcast::Gitx::CLI.start ['nuke', 'prototype', '--destination', 'master']
321
337
  end
322
338
  it 'should publish message into socialcast' do end # see expectations
323
339
  it 'should run expected commands' do
324
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
340
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
325
341
  "git checkout master",
326
342
  "git branch -D last_known_good_master",
327
343
  "git fetch origin",
@@ -342,7 +358,7 @@ describe Socialcast::Gitx::CLI do
342
358
  "git push origin last_known_good_prototype",
343
359
  "git branch --set-upstream last_known_good_prototype origin/last_known_good_prototype",
344
360
  "git checkout master"
345
- ]
361
+ ])
346
362
  end
347
363
  end
348
364
  context 'when target branch == staging and --destination == last_known_good_staging' do
@@ -352,7 +368,7 @@ describe Socialcast::Gitx::CLI do
352
368
  Socialcast::Gitx::CLI.start ['nuke', 'staging', '--destination', 'last_known_good_staging']
353
369
  end
354
370
  it 'should run expected commands' do
355
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
371
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
356
372
  "git checkout master",
357
373
  "git branch -D last_known_good_staging",
358
374
  "git fetch origin",
@@ -363,18 +379,18 @@ describe Socialcast::Gitx::CLI do
363
379
  "git push origin staging",
364
380
  "git branch --set-upstream staging origin/staging",
365
381
  "git checkout master"
366
- ]
382
+ ])
367
383
  end
368
384
  end
369
385
  context 'when target branch == prototype and destination prompt == nil' do
370
386
  before do
371
387
  stub_message "#worklog resetting prototype branch to last_known_good_prototype #scgitx\n/cc @SocialcastDevelopers"
372
388
 
373
- Socialcast::Gitx::CLI.any_instance.should_receive(:ask).and_return('')
389
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:ask).and_return('')
374
390
  Socialcast::Gitx::CLI.start ['nuke', 'prototype']
375
391
  end
376
392
  it 'defaults to last_known_good_prototype and should run expected commands' do
377
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
393
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
378
394
  "git checkout master",
379
395
  "git branch -D last_known_good_prototype",
380
396
  "git fetch origin",
@@ -385,18 +401,18 @@ describe Socialcast::Gitx::CLI do
385
401
  "git push origin prototype",
386
402
  "git branch --set-upstream prototype origin/prototype",
387
403
  "git checkout master"
388
- ]
404
+ ])
389
405
  end
390
406
  end
391
407
  context 'when target branch == prototype and destination prompt = master' do
392
408
  before do
393
409
  stub_message "#worklog resetting prototype branch to last_known_good_master #scgitx\n/cc @SocialcastDevelopers"
394
410
 
395
- Socialcast::Gitx::CLI.any_instance.should_receive(:ask).and_return('master')
411
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:ask).and_return('master')
396
412
  Socialcast::Gitx::CLI.start ['nuke', 'prototype']
397
413
  end
398
414
  it 'should run expected commands' do
399
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
415
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
400
416
  "git checkout master",
401
417
  "git branch -D last_known_good_master",
402
418
  "git fetch origin",
@@ -417,19 +433,415 @@ describe Socialcast::Gitx::CLI do
417
433
  "git push origin last_known_good_prototype",
418
434
  "git branch --set-upstream last_known_good_prototype origin/last_known_good_prototype",
419
435
  "git checkout master"
420
- ]
436
+ ])
421
437
  end
422
438
  end
423
439
  context 'when target branch != staging || prototype' do
424
440
  it 'should raise error' do
425
- lambda {
426
- Socialcast::Gitx::CLI.any_instance.should_receive(:ask).and_return('master')
441
+ expect {
442
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:ask).and_return('master')
427
443
  Socialcast::Gitx::CLI.start ['nuke', 'asdfasdf']
428
- }.should raise_error(/Only aggregate branches are allowed to be reset/)
444
+ }.to raise_error(/Only aggregate branches are allowed to be reset/)
429
445
  end
430
446
  end
431
447
  end
432
448
 
449
+ describe '#backportpr' do
450
+ before do
451
+ # https://developer.github.com/v3/search/#search-issues
452
+ pr_response = {
453
+ "url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls/59",
454
+ "id" => 13712197,
455
+ "html_url" => "https://github.com/socialcast/socialcast-git-extensions/pull/59",
456
+ "diff_url" => "https://github.com/socialcast/socialcast-git-extensions/pull/59.diff",
457
+ "patch_url" => "https://github.com/socialcast/socialcast-git-extensions/pull/59.patch",
458
+ "issue_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/issues/59",
459
+ "number" => 59,
460
+ "state" => "closed",
461
+ "title" => "additional-notifications",
462
+ "user" => {
463
+ "login" => "MikeSilvis",
464
+ "id" => 152323,
465
+ "avatar_url" => "https://avatars.githubusercontent.com/u/152323?",
466
+ "gravatar_id" => "1bb5f2e12dcbfb8c103689f4ae94f431",
467
+ "url" => "https://api.github.com/users/MikeSilvis",
468
+ "html_url" => "https://github.com/MikeSilvis",
469
+ "followers_url" => "https://api.github.com/users/MikeSilvis/followers",
470
+ "following_url" => "https://api.github.com/users/MikeSilvis/following{/other_user}",
471
+ "gists_url" => "https://api.github.com/users/MikeSilvis/gists{/gist_id}",
472
+ "starred_url" => "https://api.github.com/users/MikeSilvis/starred{/owner}{/repo}",
473
+ "subscriptions_url" => "https://api.github.com/users/MikeSilvis/subscriptions",
474
+ "organizations_url" => "https://api.github.com/users/MikeSilvis/orgs",
475
+ "repos_url" => "https://api.github.com/users/MikeSilvis/repos",
476
+ "events_url" => "https://api.github.com/users/MikeSilvis/events{/privacy}",
477
+ "received_events_url" => "https://api.github.com/users/MikeSilvis/received_events",
478
+ "type" => "User",
479
+ "site_admin" => false
480
+ },
481
+ "body" => "simply testing this out",
482
+ "created_at" => "2014-03-18T22:39:37Z",
483
+ "updated_at" => "2014-03-18T22:40:18Z",
484
+ "closed_at" => "2014-03-18T22:39:46Z",
485
+ "merged_at" => nil,
486
+ "merge_commit_sha" => "f73009f4eb245c84da90e8abf9be846c58bc1e3b",
487
+ "assignee" => nil,
488
+ "milestone" => nil,
489
+ "commits_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls/59/commits",
490
+ "review_comments_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls/59/comments",
491
+ "review_comment_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls/comments/{number}",
492
+ "comments_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/issues/59/comments",
493
+ "statuses_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/statuses/5e30d5af3f4d1bb3a34cc97568299be028b65f6f",
494
+ "head" => {
495
+ "label" => "socialcast:additional-notifications",
496
+ "ref" => "additional-notifications",
497
+ "sha" => "5e30d5af3f4d1bb3a34cc97568299be028b65f6f",
498
+ "user" => {
499
+ "login" => "socialcast",
500
+ "id" => 57931,
501
+ "avatar_url" => "https://avatars.githubusercontent.com/u/57931?",
502
+ "gravatar_id" => "489ec347da22410e9770ea022e6e2038",
503
+ "url" => "https://api.github.com/users/socialcast",
504
+ "html_url" => "https://github.com/socialcast",
505
+ "followers_url" => "https://api.github.com/users/socialcast/followers",
506
+ "following_url" => "https://api.github.com/users/socialcast/following{/other_user}",
507
+ "gists_url" => "https://api.github.com/users/socialcast/gists{/gist_id}",
508
+ "starred_url" => "https://api.github.com/users/socialcast/starred{/owner}{/repo}",
509
+ "subscriptions_url" => "https://api.github.com/users/socialcast/subscriptions",
510
+ "organizations_url" => "https://api.github.com/users/socialcast/orgs",
511
+ "repos_url" => "https://api.github.com/users/socialcast/repos",
512
+ "events_url" => "https://api.github.com/users/socialcast/events{/privacy}",
513
+ "received_events_url" => "https://api.github.com/users/socialcast/received_events",
514
+ "type" => "Organization",
515
+ "site_admin" => false
516
+ },
517
+ "repo" => {
518
+ "id" => 1000634,
519
+ "name" => "socialcast-git-extensions",
520
+ "full_name" => "socialcast/socialcast-git-extensions",
521
+ "owner" => {
522
+ "login" => "socialcast",
523
+ "id" => 57931,
524
+ "avatar_url" => "https://avatars.githubusercontent.com/u/57931?",
525
+ "gravatar_id" => "489ec347da22410e9770ea022e6e2038",
526
+ "url" => "https://api.github.com/users/socialcast",
527
+ "html_url" => "https://github.com/socialcast",
528
+ "followers_url" => "https://api.github.com/users/socialcast/followers",
529
+ "following_url" => "https://api.github.com/users/socialcast/following{/other_user}",
530
+ "gists_url" => "https://api.github.com/users/socialcast/gists{/gist_id}",
531
+ "starred_url" => "https://api.github.com/users/socialcast/starred{/owner}{/repo}",
532
+ "subscriptions_url" => "https://api.github.com/users/socialcast/subscriptions",
533
+ "organizations_url" => "https://api.github.com/users/socialcast/orgs",
534
+ "repos_url" => "https://api.github.com/users/socialcast/repos",
535
+ "events_url" => "https://api.github.com/users/socialcast/events{/privacy}",
536
+ "received_events_url" => "https://api.github.com/users/socialcast/received_events",
537
+ "type" => "Organization",
538
+ "site_admin" => false
539
+ },
540
+ "private" => false,
541
+ "html_url" => "https://github.com/socialcast/socialcast-git-extensions",
542
+ "description" => "",
543
+ "fork" => false,
544
+ "url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions",
545
+ "forks_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/forks",
546
+ "keys_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/keys{/key_id}",
547
+ "collaborators_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/collaborators{/collaborator}",
548
+ "teams_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/teams",
549
+ "hooks_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/hooks",
550
+ "issue_events_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/issues/events{/number}",
551
+ "events_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/events",
552
+ "assignees_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/assignees{/user}",
553
+ "branches_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/branches{/branch}",
554
+ "tags_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/tags",
555
+ "blobs_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/git/blobs{/sha}",
556
+ "git_tags_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/git/tags{/sha}",
557
+ "git_refs_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/git/refs{/sha}",
558
+ "trees_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/git/trees{/sha}",
559
+ "statuses_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/statuses/{sha}",
560
+ "languages_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/languages",
561
+ "stargazers_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/stargazers",
562
+ "contributors_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/contributors",
563
+ "subscribers_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/subscribers",
564
+ "subscription_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/subscription",
565
+ "commits_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/commits{/sha}",
566
+ "git_commits_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/git/commits{/sha}",
567
+ "comments_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/comments{/number}",
568
+ "issue_comment_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/issues/comments/{number}",
569
+ "contents_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/contents/{+path}",
570
+ "compare_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/compare/{base}...{head}",
571
+ "merges_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/merges",
572
+ "archive_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/{archive_format}{/ref}",
573
+ "downloads_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/downloads",
574
+ "issues_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/issues{/number}",
575
+ "pulls_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls{/number}",
576
+ "milestones_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/milestones{/number}",
577
+ "notifications_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/notifications{?since,all,participating}",
578
+ "labels_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/labels{/name}",
579
+ "releases_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/releases{/id}",
580
+ "created_at" => "2010-10-18T21:23:25Z",
581
+ "updated_at" => "2014-05-12T20:03:30Z",
582
+ "pushed_at" => "2014-05-12T20:03:31Z",
583
+ "git_url" => "git://github.com/socialcast/socialcast-git-extensions.git",
584
+ "ssh_url" => "git@github.com:socialcast/socialcast-git-extensions.git",
585
+ "clone_url" => "https://github.com/socialcast/socialcast-git-extensions.git",
586
+ "svn_url" => "https://github.com/socialcast/socialcast-git-extensions",
587
+ "homepage" => "",
588
+ "size" => 1719,
589
+ "stargazers_count" => 3,
590
+ "watchers_count" => 3,
591
+ "language" => "Ruby",
592
+ "has_issues" => true,
593
+ "has_downloads" => true,
594
+ "has_wiki" => true,
595
+ "forks_count" => 6,
596
+ "mirror_url" => nil,
597
+ "open_issues_count" => 13,
598
+ "forks" => 6,
599
+ "open_issues" => 13,
600
+ "watchers" => 3,
601
+ "default_branch" => "master"
602
+ }
603
+ },
604
+ "base" => {
605
+ "label" => "socialcast:master",
606
+ "ref" => "master",
607
+ "sha" => "1baae2de301c43d44297647f3f9c1e06697748ad",
608
+ "user" => {
609
+ "login" => "socialcast",
610
+ "id" => 57931,
611
+ "avatar_url" => "https://avatars.githubusercontent.com/u/57931?",
612
+ "gravatar_id" => "489ec347da22410e9770ea022e6e2038",
613
+ "url" => "https://api.github.com/users/socialcast",
614
+ "html_url" => "https://github.com/socialcast",
615
+ "followers_url" => "https://api.github.com/users/socialcast/followers",
616
+ "following_url" => "https://api.github.com/users/socialcast/following{/other_user}",
617
+ "gists_url" => "https://api.github.com/users/socialcast/gists{/gist_id}",
618
+ "starred_url" => "https://api.github.com/users/socialcast/starred{/owner}{/repo}",
619
+ "subscriptions_url" => "https://api.github.com/users/socialcast/subscriptions",
620
+ "organizations_url" => "https://api.github.com/users/socialcast/orgs",
621
+ "repos_url" => "https://api.github.com/users/socialcast/repos",
622
+ "events_url" => "https://api.github.com/users/socialcast/events{/privacy}",
623
+ "received_events_url" => "https://api.github.com/users/socialcast/received_events",
624
+ "type" => "Organization",
625
+ "site_admin" => false
626
+ },
627
+ "repo" => {
628
+ "id" => 1000634,
629
+ "name" => "socialcast-git-extensions",
630
+ "full_name" => "socialcast/socialcast-git-extensions",
631
+ "owner" => {
632
+ "login" => "socialcast",
633
+ "id" => 57931,
634
+ "avatar_url" => "https://avatars.githubusercontent.com/u/57931?",
635
+ "gravatar_id" => "489ec347da22410e9770ea022e6e2038",
636
+ "url" => "https://api.github.com/users/socialcast",
637
+ "html_url" => "https://github.com/socialcast",
638
+ "followers_url" => "https://api.github.com/users/socialcast/followers",
639
+ "following_url" => "https://api.github.com/users/socialcast/following{/other_user}",
640
+ "gists_url" => "https://api.github.com/users/socialcast/gists{/gist_id}",
641
+ "starred_url" => "https://api.github.com/users/socialcast/starred{/owner}{/repo}",
642
+ "subscriptions_url" => "https://api.github.com/users/socialcast/subscriptions",
643
+ "organizations_url" => "https://api.github.com/users/socialcast/orgs",
644
+ "repos_url" => "https://api.github.com/users/socialcast/repos",
645
+ "events_url" => "https://api.github.com/users/socialcast/events{/privacy}",
646
+ "received_events_url" => "https://api.github.com/users/socialcast/received_events",
647
+ "type" => "Organization",
648
+ "site_admin" => false
649
+ },
650
+ "private" => false,
651
+ "html_url" => "https://github.com/socialcast/socialcast-git-extensions",
652
+ "description" => "",
653
+ "fork" => false,
654
+ "url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions",
655
+ "forks_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/forks",
656
+ "keys_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/keys{/key_id}",
657
+ "collaborators_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/collaborators{/collaborator}",
658
+ "teams_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/teams",
659
+ "hooks_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/hooks",
660
+ "issue_events_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/issues/events{/number}",
661
+ "events_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/events",
662
+ "assignees_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/assignees{/user}",
663
+ "branches_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/branches{/branch}",
664
+ "tags_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/tags",
665
+ "blobs_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/git/blobs{/sha}",
666
+ "git_tags_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/git/tags{/sha}",
667
+ "git_refs_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/git/refs{/sha}",
668
+ "trees_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/git/trees{/sha}",
669
+ "statuses_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/statuses/{sha}",
670
+ "languages_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/languages",
671
+ "stargazers_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/stargazers",
672
+ "contributors_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/contributors",
673
+ "subscribers_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/subscribers",
674
+ "subscription_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/subscription",
675
+ "commits_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/commits{/sha}",
676
+ "git_commits_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/git/commits{/sha}",
677
+ "comments_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/comments{/number}",
678
+ "issue_comment_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/issues/comments/{number}",
679
+ "contents_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/contents/{+path}",
680
+ "compare_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/compare/{base}...{head}",
681
+ "merges_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/merges",
682
+ "archive_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/{archive_format}{/ref}",
683
+ "downloads_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/downloads",
684
+ "issues_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/issues{/number}",
685
+ "pulls_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls{/number}",
686
+ "milestones_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/milestones{/number}",
687
+ "notifications_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/notifications{?since,all,participating}",
688
+ "labels_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/labels{/name}",
689
+ "releases_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/releases{/id}",
690
+ "created_at" => "2010-10-18T21:23:25Z",
691
+ "updated_at" => "2014-05-12T20:03:30Z",
692
+ "pushed_at" => "2014-05-12T20:03:31Z",
693
+ "git_url" => "git://github.com/socialcast/socialcast-git-extensions.git",
694
+ "ssh_url" => "git@github.com:socialcast/socialcast-git-extensions.git",
695
+ "clone_url" => "https://github.com/socialcast/socialcast-git-extensions.git",
696
+ "svn_url" => "https://github.com/socialcast/socialcast-git-extensions",
697
+ "homepage" => "",
698
+ "size" => 1719,
699
+ "stargazers_count" => 3,
700
+ "watchers_count" => 3,
701
+ "language" => "Ruby",
702
+ "has_issues" => true,
703
+ "has_downloads" => true,
704
+ "has_wiki" => true,
705
+ "forks_count" => 6,
706
+ "mirror_url" => nil,
707
+ "open_issues_count" => 13,
708
+ "forks" => 6,
709
+ "open_issues" => 13,
710
+ "watchers" => 3,
711
+ "default_branch" => "master"
712
+ }
713
+ },
714
+ "_links" => {
715
+ "self" => {
716
+ "href" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls/59"
717
+ },
718
+ "html" => {
719
+ "href" => "https://github.com/socialcast/socialcast-git-extensions/pull/59"
720
+ },
721
+ "issue" => {
722
+ "href" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/issues/59"
723
+ },
724
+ "comments" => {
725
+ "href" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/issues/59/comments"
726
+ },
727
+ "review_comments" => {
728
+ "href" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls/59/comments"
729
+ },
730
+ "review_comment" => {
731
+ "href" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls/comments/{number}"
732
+ },
733
+ "commits" => {
734
+ "href" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls/59/commits"
735
+ },
736
+ "statuses" => {
737
+ "href" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/statuses/5e30d5af3f4d1bb3a34cc97568299be028b65f6f"
738
+ }
739
+ },
740
+ "merged" => false,
741
+ "mergeable" => true,
742
+ "mergeable_state" => "unstable",
743
+ "merged_by" => nil,
744
+ "comments" => 0,
745
+ "review_comments" => 0,
746
+ "commits" => 1,
747
+ "additions" => 14,
748
+ "deletions" => 2,
749
+ "changed_files" => 2
750
+ }
751
+
752
+ commits_response = [
753
+ {
754
+ "sha" => "5e30d5af3f4d1bb3a34cc97568299be028b65f6f",
755
+ "commit" => {
756
+ "author" => {
757
+ "name" => "Mike Silvis",
758
+ "email" => "mikesilvis@gmail.com",
759
+ "date" => "2014-03-18T22:39:12Z"
760
+ },
761
+ "committer" => {
762
+ "name" => "Mike Silvis",
763
+ "email" => "mikesilvis@gmail.com",
764
+ "date" => "2014-03-18T22:39:12Z"
765
+ },
766
+ "message" => "adding the ability to specify additional reviewers",
767
+ "tree" => {
768
+ "sha" => "dcf05deb22223997a5184cd3a1866249f3e73e3b",
769
+ "url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/git/trees/dcf05deb22223997a5184cd3a1866249f3e73e3b"
770
+ },
771
+ "url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/git/commits/5e30d5af3f4d1bb3a34cc97568299be028b65f6f",
772
+ "comment_count" => 0
773
+ },
774
+ "url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/commits/5e30d5af3f4d1bb3a34cc97568299be028b65f6f",
775
+ "html_url" => "https://github.com/socialcast/socialcast-git-extensions/commit/5e30d5af3f4d1bb3a34cc97568299be028b65f6f",
776
+ "comments_url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/commits/5e30d5af3f4d1bb3a34cc97568299be028b65f6f/comments",
777
+ "author" => {
778
+ "login" => "MikeSilvis",
779
+ "id" => 152323,
780
+ "avatar_url" => "https://avatars.githubusercontent.com/u/152323?",
781
+ "gravatar_id" => "1bb5f2e12dcbfb8c103689f4ae94f431",
782
+ "url" => "https://api.github.com/users/MikeSilvis",
783
+ "html_url" => "https://github.com/MikeSilvis",
784
+ "followers_url" => "https://api.github.com/users/MikeSilvis/followers",
785
+ "following_url" => "https://api.github.com/users/MikeSilvis/following{/other_user}",
786
+ "gists_url" => "https://api.github.com/users/MikeSilvis/gists{/gist_id}",
787
+ "starred_url" => "https://api.github.com/users/MikeSilvis/starred{/owner}{/repo}",
788
+ "subscriptions_url" => "https://api.github.com/users/MikeSilvis/subscriptions",
789
+ "organizations_url" => "https://api.github.com/users/MikeSilvis/orgs",
790
+ "repos_url" => "https://api.github.com/users/MikeSilvis/repos",
791
+ "events_url" => "https://api.github.com/users/MikeSilvis/events{/privacy}",
792
+ "received_events_url" => "https://api.github.com/users/MikeSilvis/received_events",
793
+ "type" => "User",
794
+ "site_admin" => false
795
+ },
796
+ "committer" => {
797
+ "login" => "MikeSilvis",
798
+ "id" => 152323,
799
+ "avatar_url" => "https://avatars.githubusercontent.com/u/152323?",
800
+ "gravatar_id" => "1bb5f2e12dcbfb8c103689f4ae94f431",
801
+ "url" => "https://api.github.com/users/MikeSilvis",
802
+ "html_url" => "https://github.com/MikeSilvis",
803
+ "followers_url" => "https://api.github.com/users/MikeSilvis/followers",
804
+ "following_url" => "https://api.github.com/users/MikeSilvis/following{/other_user}",
805
+ "gists_url" => "https://api.github.com/users/MikeSilvis/gists{/gist_id}",
806
+ "starred_url" => "https://api.github.com/users/MikeSilvis/starred{/owner}{/repo}",
807
+ "subscriptions_url" => "https://api.github.com/users/MikeSilvis/subscriptions",
808
+ "organizations_url" => "https://api.github.com/users/MikeSilvis/orgs",
809
+ "repos_url" => "https://api.github.com/users/MikeSilvis/repos",
810
+ "events_url" => "https://api.github.com/users/MikeSilvis/events{/privacy}",
811
+ "received_events_url" => "https://api.github.com/users/MikeSilvis/received_events",
812
+ "type" => "User",
813
+ "site_admin" => false
814
+ },
815
+ "parents" => [
816
+ {
817
+ "sha" => "1baae2de301c43d44297647f3f9c1e06697748ad",
818
+ "url" => "https://api.github.com/repos/socialcast/socialcast-git-extensions/commits/1baae2de301c43d44297647f3f9c1e06697748ad",
819
+ "html_url" => "https://github.com/socialcast/socialcast-git-extensions/commit/1baae2de301c43d44297647f3f9c1e06697748ad"
820
+ }
821
+ ]
822
+ }
823
+ ]
824
+
825
+ stub_request(:get, "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls/59").
826
+ with(:headers => { 'Accept' => 'application/json', 'Accept-Encoding' => 'gzip, deflate', 'Authorization' => /token\s\w+/, 'Content-Type' => 'application/json', 'User-Agent' => 'socialcast-git-extensions' }).
827
+ to_return(:status => 200, :body => pr_response.to_json, :headers => {})
828
+ stub_request(:get, "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls/59/commits").
829
+ with(:headers => { 'Accept' => 'application/json', 'Accept-Encoding' => 'gzip, deflate', 'Authorization' => /token\s\w+/, 'Content-Type' => 'application/json', 'User-Agent' => 'socialcast-git-extensions' }).
830
+ to_return(:status => 200, :body => commits_response.to_json, :headers => {})
831
+ stub_request(:post, "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls").
832
+ with(:body => "{\"title\":\"backport_59_to_v1.x\",\"base\":\"v1.x\",\"head\":\"backport_59_to_v1.x\",\"body\":\"Backport #59 to https://github.com/socialcast/socialcast-git-extensions/tree/v1.x\\n***\\nsimply testing this out\"}",
833
+ :headers => { 'Accept' => 'application/json', 'Accept-Encoding' => 'gzip, deflate', 'Authorization' => /token\s\w+/, 'Content-Type' => 'application/json', 'User-Agent'=>'socialcast-git-extensions' }).
834
+ to_return(:status => 200, :body => '{"html_url": "https://github.com/socialcast/socialcast-git-extensions/pulls/60"}', :headers => { 'Content-Type' => 'application/json' })
835
+
836
+ stub_message "#reviewrequest backport #59 to v1.x #scgitx\n\n/cc @SocialcastDevelopers", :url => 'https://github.com/socialcast/socialcast-git-extensions/pulls/60', :message_type => 'review_request'
837
+
838
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:backportpr).and_call_original
839
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:post).with("#reviewrequest backport #59 to v1.x #scgitx\n\n/cc @SocialcastDevelopers", { :url => "https://github.com/socialcast/socialcast-git-extensions/pulls/60", :message_type => "review_request" })
840
+ Socialcast::Gitx::CLI.start ['backportpr', '59', 'v1.x']
841
+ end
842
+ it 'creates a branch based on v1.x and cherry-picks in PR 59' do end
843
+ end
844
+
433
845
  describe '#findpr' do
434
846
  before do
435
847
  # https://developer.github.com/v3/search/#search-issues
@@ -485,42 +897,38 @@ describe Socialcast::Gitx::CLI do
485
897
  }
486
898
 
487
899
  stub_request(:get, "https://api.github.com/search/issues?q=abc123%20type:pr%20repo:socialcast/socialcast-git-extensions").
488
- with(:headers => {'Accept'=>'application/json', 'Accept-Encoding'=>'gzip, deflate', 'Authorization'=>/token\s\w+/, 'Content-Type'=>'application/json', 'User-Agent'=>'Ruby'}).
900
+ with(:headers => { 'Accept' => 'application/json', 'Accept-Encoding' => 'gzip, deflate', 'Authorization' => /token\s\w+/, 'Content-Type' => 'application/json', 'User-Agent' => 'socialcast-git-extensions'}).
489
901
  to_return(:status => 200, :body => stub_response.to_json, :headers => {})
490
- Socialcast::Gitx::CLI.any_instance.should_receive(:findpr).and_call_original
491
- Socialcast::Gitx::CLI.any_instance.stub(:say).with do |message|
492
- @said_text = @said_text.to_s + message
493
- end
902
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:findpr).and_call_original
903
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:say).with("Searching github pull requests for abc123")
904
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:say).with("\nhttps://github.com/batterseapower/pinyin-toolkit/issues/132\n\tLine Number Indexes Beyond 20 Not Displayed\n\tNick3C 2009-07-12T20:10:41Z")
494
905
  Socialcast::Gitx::CLI.start ['findpr', 'abc123']
495
906
  end
496
- it 'fetches the data from github and prints it out' do
497
- @said_text.should include "https://github.com/batterseapower/pinyin-toolkit/issues/132"
498
- @said_text.should include "Nick3C"
499
- @said_text.should include "Line Number Indexes Beyond 20 Not Displayed"
500
- end
907
+ it 'fetches the data from github and prints it out' do end
501
908
  end
502
909
 
503
910
  describe '#reviewrequest' do
504
911
  context 'when there are no review_buddies specified' do
505
912
  before do
506
- Socialcast::Gitx::CLI.any_instance.stub(:config_file).and_return(Pathname(''))
913
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:config_file).and_return(Pathname(''))
507
914
  end
508
- context 'when description != null' do
915
+ context 'when description != nil' do
509
916
  before do
510
917
  stub_request(:post, "https://api.github.com/repos/socialcast/socialcast-git-extensions/pulls").
511
918
  to_return(:status => 200, :body => %q({"html_url": "http://github.com/repo/project/pulls/1"}), :headers => {})
512
919
 
513
- stub_message "#reviewrequest for FOO #scgitx\n\n/cc @SocialcastDevelopers\n\ntesting\n\n", :url => 'http://github.com/repo/project/pulls/1', :message_type => 'review_request'
920
+ stub_message "#reviewrequest for FOO #scgitx\n\n/cc @SocialcastDevelopers\n\ntesting\n\n1 file changed", :url => 'http://github.com/repo/project/pulls/1', :message_type => 'review_request'
921
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:changelog_summary).and_return('1 file changed')
514
922
  Socialcast::Gitx::CLI.start ['reviewrequest', '--description', 'testing', '-s']
515
923
  end
516
924
  it 'should create github pull request' do end # see expectations
517
925
  it 'should post socialcast message' do end # see expectations
518
926
  it 'should run expected commands' do
519
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
927
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
520
928
  "git pull origin FOO",
521
929
  "git pull origin master",
522
930
  "git push origin HEAD"
523
- ]
931
+ ])
524
932
  end
525
933
  end
526
934
  end
@@ -532,8 +940,9 @@ describe Socialcast::Gitx::CLI do
532
940
  stub_request(:patch, "http://github.com/repos/repo/project/issues/1").to_return(:status => 200)
533
941
  end
534
942
  context 'and additional reviewers are specified' do
535
- let(:message_body) { "#reviewrequest for FOO #scgitx\n\n/cc @SocialcastDevelopers\n\n\nAssigned additionally to @JohnSmith for API review\n\ntesting\n\n" }
943
+ let(:message_body) { "#reviewrequest for FOO #scgitx\n\n/cc @SocialcastDevelopers\n\n\nAssigned additionally to @JohnSmith for API review\n\ntesting\n\n1 file changed" }
536
944
  before do
945
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:changelog_summary).and_return('1 file changed')
537
946
  # The Review Buddy should be @mentioned in the message
538
947
  stub_message message_body, :url => 'http://github.com/repo/project/pulls/1', :message_type => 'review_request'
539
948
  Socialcast::Gitx::CLI.start ['reviewrequest', '--description', 'testing', '-a', 'a']
@@ -541,16 +950,17 @@ describe Socialcast::Gitx::CLI do
541
950
  it 'should create github pull request' do end # see expectations
542
951
  it 'should post socialcast message' do end # see expectations
543
952
  it 'should run expected commands' do
544
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
953
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
545
954
  "git pull origin FOO",
546
955
  "git pull origin master",
547
956
  "git push origin HEAD"
548
- ]
957
+ ])
549
958
  end
550
959
  end
551
960
  context 'and additional reviewers are not specified' do
552
- let(:message_body) { "#reviewrequest for FOO #scgitx\n\n/cc @SocialcastDevelopers\n\ntesting\n\n" }
961
+ let(:message_body) { "#reviewrequest for FOO #scgitx\n\n/cc @SocialcastDevelopers\n\ntesting\n\n1 file changed" }
553
962
  before do
963
+ allow_any_instance_of(Socialcast::Gitx::CLI).to receive(:changelog_summary).and_return('1 file changed')
554
964
  # The Review Buddy should be @mentioned in the message
555
965
  stub_message message_body, :url => 'http://github.com/repo/project/pulls/1', :message_type => 'review_request'
556
966
  Socialcast::Gitx::CLI.start ['reviewrequest', '--description', 'testing', '-s']
@@ -566,7 +976,7 @@ describe Socialcast::Gitx::CLI do
566
976
  Socialcast::Gitx::CLI.start ['promote']
567
977
  end
568
978
  it 'should integrate into staging' do
569
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
979
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
570
980
  "git pull origin FOO",
571
981
  "git pull origin master",
572
982
  "git push origin HEAD",
@@ -583,24 +993,24 @@ describe Socialcast::Gitx::CLI do
583
993
  "git push origin HEAD",
584
994
  "git checkout staging",
585
995
  "git checkout FOO"
586
- ]
996
+ ])
587
997
  end
588
998
  end
589
999
 
590
1000
  describe '#cleanup' do
591
1001
  before do
592
- Socialcast::Gitx::CLI.any_instance.should_receive(:branches).with(:merged => true, :remote => true).and_return(['master', 'foobar', 'last_known_good_master'])
593
- Socialcast::Gitx::CLI.any_instance.should_receive(:branches).with(:merged => true).and_return(['staging', 'bazquux', 'last_known_good_prototype'])
1002
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:branches).with(:merged => true, :remote => true).and_return(['master', 'foobar', 'last_known_good_master'])
1003
+ expect_any_instance_of(Socialcast::Gitx::CLI).to receive(:branches).with(:merged => true).and_return(['staging', 'bazquux', 'last_known_good_prototype'])
594
1004
  Socialcast::Gitx::CLI.start ['cleanup']
595
1005
  end
596
1006
  it 'should only cleanup non-reserved branches' do
597
- Socialcast::Gitx::CLI.stubbed_executed_commands.should == [
1007
+ expect(Socialcast::Gitx::CLI.stubbed_executed_commands).to eq([
598
1008
  "git checkout master",
599
1009
  "git pull",
600
1010
  "git remote prune origin",
601
1011
  "git push origin --delete foobar",
602
1012
  "git branch -d bazquux"
603
- ]
1013
+ ])
604
1014
  end
605
1015
  end
606
1016
  end