octopolo 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1180ea8ecff06b1794c95afb8691c7577f9223c9
4
- data.tar.gz: 1a5a2e430cfb10351f755df6c2614723f72872b8
3
+ metadata.gz: a4bcb4049924fd9baffda4bd06d42effabbe247a
4
+ data.tar.gz: a1c8a5438d4ea4bec64f5f452af13da939ee1aff
5
5
  SHA512:
6
- metadata.gz: a21ed3bc2ce58fe993ec7212c78a71bb3598e5e3b88387ff9531ca4d28c467c32c8eb6277dfb1723f0e22a7f13bee03c8b24f5ef57e203ac3f6385ea4ccd5d0d
7
- data.tar.gz: 11a8c5346bcd00e22bc3f1a257993aaa736f4d87a1d86c838001da4188b2ff9611dc6c120b4460e8b0eba4ec838a921f972ba36760b5fbb04daf3f353feabb2d
6
+ metadata.gz: 950c567a168527dc9f3424667510896ac39b0798bc622035be698e350ca78092bc47f14dbf97461074951ead90733cf273aa55aa3496d08cb1023231c745bc7f
7
+ data.tar.gz: 36e758529e0cd35400ba538044cbed8a428e76be589dd75332c698d33dedaa45b4264ecd63ee160db26e384a1901d3c0837cf8ef5f83d506415b0e64c31f8920
@@ -1,3 +1,8 @@
1
+ #### v1.4.0
2
+ * Check PR status before marking deployable/accept-pull
3
+
4
+ > Arvind Menon: Brian Bergstrom, Chris Arcand: https://github.com/sportngin/octopolo/pull/107
5
+
1
6
  #### v1.3.0
2
7
  * IS-4641-spring-cleaning-jira-bomb
3
8
 
@@ -1,8 +1,9 @@
1
1
  arg :pull_request_id
2
2
  desc 'Accept pull requests. Merges the given pull request into master and updates the changelog.'
3
3
  command 'accept-pull' do |c|
4
+ c.switch [:f, :force], default_value: false, desc: 'Ignore the status checks on the pull request', negatable: false
4
5
  c.action do |global_options, options, args|
5
6
  require_relative '../scripts/accept_pull'
6
- Octopolo::Scripts::AcceptPull.execute args.first
7
+ Octopolo::Scripts::AcceptPull.execute(args.first, options)
7
8
  end
8
9
  end
@@ -1,8 +1,9 @@
1
1
  arg :pull_request_id
2
2
  desc 'Merges PR into the deployable branch'
3
3
  command 'deployable' do |c|
4
+ c.switch [:f, :force], default_value: false, desc: 'Ignore the status checks on the pull request', negatable: false
4
5
  c.action do |global_options, options, args|
5
6
  require_relative '../scripts/deployable'
6
- Octopolo::Scripts::Deployable.execute args.first
7
+ Octopolo::Scripts::Deployable.execute(args.first, options)
7
8
  end
8
9
  end
@@ -117,6 +117,10 @@ module Octopolo
117
117
  client.search_issues *args
118
118
  end
119
119
 
120
+ def self.status *args
121
+ client.status *args
122
+ end
123
+
120
124
 
121
125
  # now that you've set up your credentials, try again
122
126
  TryAgain = Class.new(StandardError)
@@ -69,6 +69,14 @@ module Octopolo
69
69
  @commits ||= Commit.for_pull_request self
70
70
  end
71
71
 
72
+ def status_checks_passed?
73
+ status == 'success'
74
+ end
75
+
76
+ def status
77
+ GitHub.status(repo_name, data.head.sha)[:state]
78
+ end
79
+
72
80
  def self.current
73
81
  current_branch = Git.current_branch
74
82
  query = "repo:#{config.github_repo} type:pr is:open head:#{current_branch}"
@@ -13,13 +13,14 @@ module Octopolo
13
13
 
14
14
  attr_accessor :pull_request_id
15
15
 
16
- def self.execute(pull_request_id)
16
+ def self.execute(pull_request_id, options)
17
17
  pull_request_id ||= Integer(cli.prompt "Pull Request ID: ")
18
- new(pull_request_id).execute
18
+ new(pull_request_id, options).execute
19
19
  end
20
20
 
21
- def initialize(pull_request_id)
21
+ def initialize(pull_request_id, options={})
22
22
  @pull_request_id = pull_request_id
23
+ @force = options[:force]
23
24
  end
24
25
 
25
26
  # Public: Perform the script
@@ -36,10 +37,16 @@ module Octopolo
36
37
  def merge pull_request
37
38
  Git.fetch
38
39
  if pull_request.mergeable?
39
- cli.perform "git merge --no-ff origin/#{pull_request.branch} -m \"Merge pull request ##{pull_request_id} from origin/#{pull_request.branch}\""
40
+ if pull_request.status_checks_passed? || @force
41
+ cli.perform "git merge --no-ff origin/#{pull_request.branch} -m \"Merge pull request ##{pull_request_id} from origin/#{pull_request.branch}\""
42
+ else
43
+ cli.say 'Status checks have not passed on this pull request.'
44
+ exit!
45
+ end
40
46
  else
41
47
  cli.say "There is a merge conflict with this branch and #{config.deploy_branch}."
42
48
  cli.say "Please update this branch with #{config.deploy_branch} or perform the merge manually and fix any conflicts"
49
+ exit!
43
50
  end
44
51
  end
45
52
 
@@ -10,16 +10,17 @@ module Octopolo
10
10
 
11
11
  attr_accessor :pull_request_id
12
12
 
13
- def self.execute(pull_request_id=nil)
14
- new(pull_request_id).execute
13
+ def self.execute(pull_request_id=nil, options={})
14
+ new(pull_request_id, options).execute
15
15
  end
16
16
 
17
17
  def self.deployable_label
18
18
  Octopolo::GitHub::Label.new(name: "deployable", color: "428BCA")
19
19
  end
20
20
 
21
- def initialize(pull_request_id=nil)
21
+ def initialize(pull_request_id=nil, options={})
22
22
  @pull_request_id = pull_request_id
23
+ @force = options[:force]
23
24
  end
24
25
 
25
26
  # Public: Perform the script
@@ -30,6 +31,10 @@ module Octopolo
30
31
  end
31
32
  self.pull_request_id ||= cli.prompt("Pull Request ID: ")
32
33
  GitHub.connect do
34
+ unless deployable? || @force
35
+ CLI.say 'Pull request status checks have not passed. Cannot be marked deployable.'
36
+ exit!
37
+ end
33
38
  if config.deployable_label
34
39
  with_labelling do
35
40
  merge
@@ -46,13 +51,22 @@ module Octopolo
46
51
  private :merge
47
52
 
48
53
  def with_labelling(&block)
49
- pull_request = Octopolo::GitHub::PullRequest.new(config.github_repo, @pull_request_id)
50
54
  pull_request.add_labels(Deployable.deployable_label)
51
55
  unless yield
52
56
  pull_request.remove_labels(Deployable.deployable_label)
53
57
  end
54
58
  end
55
59
  private :with_labelling
60
+
61
+ def deployable?
62
+ pull_request.mergeable? && pull_request.status_checks_passed?
63
+ end
64
+ private :deployable?
65
+
66
+ def pull_request
67
+ @pull_request ||= Octopolo::GitHub::PullRequest.new(config.github_repo, @pull_request_id)
68
+ end
69
+ private :pull_request
56
70
  end
57
71
  end
58
72
  end
@@ -1,3 +1,3 @@
1
1
  module Octopolo
2
- VERSION = "1.3.0"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -47,8 +47,8 @@ module Octopolo
47
47
  let(:pull_request) { stub(branch: "foobranch") }
48
48
  before { subject.stub(:pull_request_id => pull_request_id) }
49
49
 
50
- context "when mergeable" do
51
- before { pull_request.stub(mergeable?: true) }
50
+ context "when mergeable and status checks passed" do
51
+ before { pull_request.stub(mergeable?: true, status_checks_passed?: true) }
52
52
 
53
53
  it "fetches and merges the request's branch" do
54
54
  Git.should_receive(:fetch)
@@ -59,7 +59,10 @@ module Octopolo
59
59
  end
60
60
 
61
61
  context "when not mergeable" do
62
- before { pull_request.stub(mergeable?: false) }
62
+ before do
63
+ pull_request.stub(mergeable?: false)
64
+ allow(subject).to receive(:exit!)
65
+ end
63
66
 
64
67
  it "performs the merge and alerts about potential failures" do
65
68
  Git.should_receive(:fetch)
@@ -67,6 +70,36 @@ module Octopolo
67
70
  cli.should_not_receive(:perform).with "git merge --no-ff origin/#{pull_request.branch} -m \"Merge pull request ##{pull_request_id} from origin/#{pull_request.branch}\""
68
71
 
69
72
  cli.should_receive(:say).with /merge conflict/
73
+ expect(subject).to receive(:exit!)
74
+ subject.merge pull_request
75
+ end
76
+ end
77
+
78
+ context "when mergeable and status checks have not passed" do
79
+ before do
80
+ pull_request.stub(mergeable?: true, status_checks_passed?: false)
81
+ allow(subject).to receive(:exit!)
82
+ end
83
+
84
+ it "performs the merge and alerts about potential failures" do
85
+ Git.should_receive(:fetch)
86
+ cli.stub(:say)
87
+ cli.should_not_receive(:perform).with "git merge --no-ff origin/#{pull_request.branch} -m \"Merge pull request ##{pull_request_id} from origin/#{pull_request.branch}\""
88
+
89
+ cli.should_receive(:say).with 'Status checks have not passed on this pull request.'
90
+ expect(subject).to receive(:exit!)
91
+ subject.merge pull_request
92
+ end
93
+ end
94
+
95
+ context "when failed status checks should be ignored" do
96
+ subject { described_class.new(pull_request_id, force: true) }
97
+ before { pull_request.stub(mergeable?: true, status_checks_passed?: false) }
98
+
99
+ it "fetches and merges the request's branch" do
100
+ Git.should_receive(:fetch)
101
+ cli.should_receive(:perform).with "git merge --no-ff origin/#{pull_request.branch} -m \"Merge pull request ##{pull_request_id} from origin/#{pull_request.branch}\""
102
+
70
103
  subject.merge pull_request
71
104
  end
72
105
  end
@@ -10,7 +10,11 @@ module Octopolo
10
10
  let(:config) { stub(user_notifications: ['NickLaMuro'],
11
11
  github_repo: 'grumpy_cat',
12
12
  deployable_label: true) }
13
- let(:pull_request) { stub(add_labels: true, remove_labels: true, number: 7) }
13
+ let(:pull_request) { stub(add_labels: true,
14
+ remove_labels: true,
15
+ number: 7,
16
+ mergeable?: true,
17
+ status_checks_passed?: true) }
14
18
  before do
15
19
  allow(subject).to receive(:cli) { cli }
16
20
  allow(subject).to receive(:config) { config }
@@ -97,6 +101,40 @@ module Octopolo
97
101
  pull_request.should_not_receive(:add_labels)
98
102
  end
99
103
  end
104
+
105
+ context "when pr is not mergeable" do
106
+ before do
107
+ pull_request.stub(mergeable?: false)
108
+ allow(subject).to receive(:exit!)
109
+ end
110
+
111
+ it "prints out an error and exits" do
112
+ expect(CLI).to receive(:say).with("Pull request status checks have not passed. Cannot be marked deployable.")
113
+ expect(subject).to receive(:exit!)
114
+ end
115
+ end
116
+
117
+ context "when pr has not passed status checks" do
118
+ before do
119
+ pull_request.stub(status_checks_passed?: false)
120
+ allow(subject).to receive(:exit!)
121
+ end
122
+
123
+ it "prints out an error and exits" do
124
+ expect(CLI).to receive(:say).with("Pull request status checks have not passed. Cannot be marked deployable.")
125
+ expect(subject).to receive(:exit!)
126
+ end
127
+ end
128
+
129
+ context "when failed status checks should be ignored" do
130
+ subject { described_class.new(42, force: true) }
131
+ before { pull_request.stub(status_checks_passed?: false) }
132
+
133
+ it "adds the deployable label" do
134
+ pull_request.should_receive(:add_labels)
135
+ end
136
+ end
137
+
100
138
  end
101
139
  end
102
140
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: octopolo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrick Byrne
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-06-16 00:00:00.000000000 Z
13
+ date: 2016-11-17 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: gli
@@ -220,7 +220,6 @@ files:
220
220
  - lib/octopolo/commands/octopolo_setup.rb
221
221
  - lib/octopolo/commands/pivotal_auth.rb
222
222
  - lib/octopolo/commands/pull_request.rb
223
- - lib/octopolo/commands/signoff.rb
224
223
  - lib/octopolo/commands/stage_up.rb
225
224
  - lib/octopolo/commands/stale_branches.rb
226
225
  - lib/octopolo/commands/sync_branch.rb
@@ -256,7 +255,6 @@ files:
256
255
  - lib/octopolo/scripts/octopolo_setup.rb
257
256
  - lib/octopolo/scripts/pivotal_auth.rb
258
257
  - lib/octopolo/scripts/pull_request.rb
259
- - lib/octopolo/scripts/signoff.rb
260
258
  - lib/octopolo/scripts/stage_up.rb
261
259
  - lib/octopolo/scripts/stale_branches.rb
262
260
  - lib/octopolo/scripts/sync_branch.rb
@@ -298,7 +296,6 @@ files:
298
296
  - spec/octopolo/scripts/octopolo_setup_spec.rb
299
297
  - spec/octopolo/scripts/pivotal_auth_spec.rb
300
298
  - spec/octopolo/scripts/pull_request_spec.rb
301
- - spec/octopolo/scripts/signoff_spec.rb
302
299
  - spec/octopolo/scripts/stage_up_spec.rb
303
300
  - spec/octopolo/scripts/stale_branches_spec.rb
304
301
  - spec/octopolo/scripts/sync_branch_spec.rb
@@ -368,7 +365,6 @@ test_files:
368
365
  - spec/octopolo/scripts/octopolo_setup_spec.rb
369
366
  - spec/octopolo/scripts/pivotal_auth_spec.rb
370
367
  - spec/octopolo/scripts/pull_request_spec.rb
371
- - spec/octopolo/scripts/signoff_spec.rb
372
368
  - spec/octopolo/scripts/stage_up_spec.rb
373
369
  - spec/octopolo/scripts/stale_branches_spec.rb
374
370
  - spec/octopolo/scripts/sync_branch_spec.rb
@@ -1,10 +0,0 @@
1
- arg :pull_request_id
2
-
3
- desc 'Provide standardized signoff message to a pull request.'
4
- long_desc "pull_request_id - The ID of the pull request to sign off on"
5
- command 'signoff' do |c|
6
- c.action do |global_options, options, args|
7
- require_relative '../scripts/signoff'
8
- Octopolo::Scripts::Signoff.execute args.first
9
- end
10
- end
@@ -1,85 +0,0 @@
1
- require_relative "../scripts"
2
- require_relative "../github"
3
-
4
- module Octopolo
5
- module Scripts
6
- class Signoff
7
- include ConfigWrapper
8
- include CLIWrapper
9
-
10
- attr_accessor :pull_request_id
11
- attr_accessor :pull_request
12
- attr_accessor :signoff_type
13
-
14
- TYPES = [
15
- "code review only",
16
- "QA only",
17
- "both code review and QA",
18
- ]
19
-
20
- def self.execute(pull_request_id=nil)
21
- new(pull_request_id).execute
22
- end
23
-
24
- def initialize(pull_request_id=nil)
25
- @pull_request_id = pull_request_id
26
- @pull_request_id ||= cli.prompt("Pull Request ID: ")
27
- end
28
-
29
- def execute
30
- preamble
31
- ask_signoff_type
32
- write_comment
33
- open_pull_request
34
- rescue WrongChoice
35
- retry
36
- end
37
-
38
- # Private: Display information about the pull request
39
- def preamble
40
- cli.say %Q(Please review "#{pull_request.title}":)
41
- cli.say pull_request.url
42
- cli.spacer_line
43
- end
44
- private :preamble
45
-
46
- # Private: Ask which type of signoff to perform
47
- def ask_signoff_type
48
- self.signoff_type = cli.ask "Which type of signoff are you performing?", TYPES
49
- end
50
- private :ask_signoff_type
51
-
52
- # Private: Find the pull request to be signed off on
53
- #
54
- # Returns a GitHub::PullRequest
55
- def pull_request
56
- @pull_request ||= GitHub::PullRequest.new config.github_repo, Integer(pull_request_id)
57
- end
58
- private :pull_request
59
- private :pull_request=
60
-
61
- # Private: The body of the comment for the given signoff
62
- #
63
- # Returns a String
64
- def comment_body
65
- "Signing off on **#{signoff_type}**."
66
- end
67
- private :comment_body
68
-
69
- # Private: Submit a comment to the pull request
70
- def write_comment
71
- pull_request.write_comment comment_body
72
- end
73
- private :write_comment
74
-
75
- # Private: Open the pull request in the browser
76
- def open_pull_request
77
- cli.open pull_request.url
78
- end
79
-
80
- WrongChoice = Class.new StandardError
81
- end
82
- end
83
- end
84
-
85
- # vim: set ft=ruby: #
@@ -1,139 +0,0 @@
1
- require "spec_helper"
2
- require "octopolo/scripts/signoff"
3
-
4
- module Octopolo
5
- module Scripts
6
- describe Signoff do
7
- # stub any attributes in the config that you need
8
- let(:config) { stub(:config, github_repo: "sportngin/foo") }
9
- let(:cli) { stub(:cli) }
10
- let(:pull_request_id) { 123 }
11
- let(:pull_request) { stub(:pull_request, url: "http://example.com") }
12
-
13
- subject { Signoff.new }
14
- before do
15
- cli.stub(:prompt)
16
- Signoff.any_instance.stub(:cli => cli, :config => config)
17
- end
18
-
19
- context "#new" do
20
- it "sets the pull_request_id if passed in from args" do
21
- expect(Signoff.new(pull_request_id.to_s).pull_request_id).to eq pull_request_id.to_s
22
- end
23
-
24
- it "prompts if no pull_request_id is given" do
25
- cli.should_receive(:prompt)
26
- .with("Pull Request ID: ")
27
- .and_return("42")
28
- expect(Signoff.new.pull_request_id).to eq "42"
29
- end
30
- end
31
-
32
- context "#execute" do
33
- it "asks which type of signoff is being performed and posts a prefab comment" do
34
- subject.should_receive(:preamble)
35
- subject.should_receive(:ask_signoff_type)
36
- subject.should_receive(:write_comment)
37
- subject.should_receive(:open_pull_request)
38
- subject.execute
39
- end
40
- end
41
-
42
- context "#preamble" do
43
- before do
44
- pull_request.stub({
45
- title: "Test PR",
46
- number: pull_request_id,
47
- url: "http://example.com/",
48
- })
49
- subject.send(:pull_request=, pull_request)
50
- end
51
-
52
- it "displays information about the given pull request" do
53
- cli.should_receive(:say).with(%Q(Please review "#{pull_request.title}":))
54
- cli.should_receive(:say).with(pull_request.url)
55
- cli.should_receive(:spacer_line)
56
-
57
- subject.send(:preamble)
58
- end
59
- end
60
-
61
- context "#ask_signoff_type" do
62
- let(:selected_type) { Signoff::TYPES.first }
63
-
64
- it "asks user to choose which signoff type to perform and remebers it" do
65
- cli.should_receive(:ask).with("Which type of signoff are you performing?", Signoff::TYPES) { selected_type }
66
- subject.send(:ask_signoff_type)
67
- expect(subject.signoff_type).to eq selected_type
68
- end
69
- end
70
-
71
- context "#write_comment" do
72
- let(:body) { "asdf" }
73
- before do
74
- subject.send(:pull_request=, pull_request)
75
- subject.stub(:comment_body) { body }
76
- end
77
-
78
- it "submits a comment that the pull request is signed off" do
79
- pull_request.should_receive(:write_comment).with(body)
80
-
81
- subject.send(:write_comment)
82
- end
83
- end
84
-
85
- context "#comment_body" do
86
- let(:selected_type) { Signoff::TYPES.first }
87
-
88
- before do
89
- subject.signoff_type = selected_type
90
- end
91
-
92
- it "injects the signoff type" do
93
- expect(subject.send(:comment_body)).to eq "Signing off on **#{selected_type}**."
94
- end
95
- end
96
-
97
- context "#open_pull_request" do
98
- before do
99
- subject.send(:pull_request=, pull_request)
100
- end
101
-
102
- it "opens the pull request in the browser" do
103
- cli.should_receive(:open).with(pull_request.url)
104
- subject.send(:open_pull_request)
105
- end
106
- end
107
-
108
- context "#pull_request" do
109
- before do
110
- subject.pull_request_id = pull_request_id
111
- end
112
-
113
- it "fetches the pull request matching the ID" do
114
- GitHub::PullRequest.should_receive(:new).with(config.github_repo, pull_request_id) { pull_request }
115
- expect(subject.send(:pull_request)).to eq pull_request
116
- end
117
-
118
- it "caches that object" do
119
- GitHub::PullRequest.should_receive(:new).once.and_return(pull_request)
120
- subject.send(:pull_request)
121
- subject.send(:pull_request)
122
- end
123
-
124
- it "remembers the pull request given to it" do
125
- GitHub::PullRequest.should_not_receive(:new)
126
- subject.send(:pull_request=, pull_request)
127
- expect(subject.send(:pull_request)).to eq pull_request
128
- end
129
-
130
- it "fails if the pull_request_id is not an int" do
131
- subject.pull_request_id = 'foo'
132
- expect { subject.send(:pull_request) }.to raise_error ArgumentError
133
- end
134
- end
135
- end
136
- end
137
- end
138
-
139
- # vim: set ft=ruby : #