octopolo 1.3.0 → 1.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.
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 : #