spec/unit/lita/handlers/github_pr_spec.rb in lita-github-0.0.3 vs spec/unit/lita/handlers/github_pr_spec.rb in lita-github-0.0.4

- old
+ new

@@ -8,22 +8,371 @@ it { routes_command('shipit #42 GrapeDuty/lita-test').to(:pr_merge) } let(:github_pr) { Lita::Handlers::GithubPR.new('robot') } let(:github_org) { 'GrapeDuty' } let(:github_repo) { 'lita-test' } + let(:full_name) { "#{github_org}/#{github_repo}" } let(:disabled_reply) { 'Sorry, this function has either been disabled or not enabled in the config' } + #### + # Helper Methods + #### describe '.pr_match' do it 'should return the content of the match data' do mock_md = { 'org' => github_org, 'repo' => github_repo, 'pr' => 42 } mock_resp = double('Lita::Response', match_data: mock_md) expect(github_pr.send(:pr_match, mock_resp)).to eql [github_org, github_repo, 42] end end describe '.merge_pr' do before do + @octo_obj = double('Octokit::Client', merge_pull_request: :ohai) + allow(github_pr).to receive(:octo).and_return(@octo_obj) + end + + let(:pr_num) { 42 } + let(:ref) { '1234567890' } + + context 'when all goes to plan' do + it 'should call octo.merge_pull_request with the proper args' do + expect(@octo_obj).to receive(:merge_pull_request).with(full_name, pr_num, ref) + .and_return(:ohai) + github_pr.send(:merge_pr, github_org, github_repo, pr_num, ref) + end + + it 'should return the return of octo.merge_pull_request' do + x = github_pr.send(:merge_pr, github_org, github_repo, 42, '1234567890') + expect(x).to eql :ohai + end + end + + context 'when the merging throws an exception' do + before do + allow(@octo_obj).to receive(:merge_pull_request).with(full_name, pr_num, ref) + .and_raise(StandardError.new) + end + + it 'should return nil' do + expect(github_pr.send(:merge_pr, github_org, github_repo, pr_num, ref)).to be_nil + end + end + end + + describe '.build_pr_header!' do + let(:pr_obj) do + { title: 'abc123', number: 42, html_url: 'https://github.com/' } + end + + it 'should return a Hash' do + info = {} + x = github_pr.send(:build_pr_header!, info, pr_obj) + expect(x).to be_an_instance_of Hash + end + + it 'should set the :title key' do + info = {} + github_pr.send(:build_pr_header!, info, pr_obj) + expect(info[:title]).to eql pr_obj[:title] + end + + it 'should set the :number key' do + info = {} + github_pr.send(:build_pr_header!, info, pr_obj) + expect(info[:number]).to eql pr_obj[:number] + end + + it 'should set the :url key' do + info = {} + github_pr.send(:build_pr_header!, info, pr_obj) + expect(info[:url]).to eql pr_obj[:html_url] + end + end + + describe '.build_pr_commitinfo!' do + let(:pr_obj) do + { + commits: 1, additions: 4, deletions: 2, changed_files: 1, + head: { sha: '1234567890' }, base: { sha: '0987654321' } + } + end + let(:info) { {} } + + it 'should return a Hash' do + expect(github_pr.send(:build_pr_commitinfo!, info, pr_obj)).to be_an_instance_of Hash + end + + it 'should set the :commits key' do + github_pr.send(:build_pr_commitinfo!, info, pr_obj) + expect(info[:commits]).to eql pr_obj[:commits] + end + + it 'should set the :plus key' do + github_pr.send(:build_pr_commitinfo!, info, pr_obj) + expect(info[:plus]).to eql pr_obj[:additions] + end + + it 'should set the :minus key' do + github_pr.send(:build_pr_commitinfo!, info, pr_obj) + expect(info[:minus]).to eql pr_obj[:deletions] + end + + it 'should set the :changed_files key' do + github_pr.send(:build_pr_commitinfo!, info, pr_obj) + expect(info[:changed_files]).to eql pr_obj[:changed_files] + end + + it 'should set the :pr_sha key' do + github_pr.send(:build_pr_commitinfo!, info, pr_obj) + expect(info[:pr_sha]).to eql pr_obj[:head][:sha] + end + + it 'should be set the :base_sha key' do + github_pr.send(:build_pr_commitinfo!, info, pr_obj) + expect(info[:base_sha]).to eql pr_obj[:base][:sha] + end + + it 'should set the :pr_sha_short key' do + github_pr.send(:build_pr_commitinfo!, info, pr_obj) + expect(info[:pr_sha_short]).to eql info[:pr_sha].slice(0, 7) + end + end + + describe '.build_pr_status!' do + before do + @user_obj = { name: 'Tim Heckman' } + @cs_obj = { state: 'success' } + @octo_obj = double('Octokit::Client', user: @user_obj, combined_status: @cs_obj) + allow(github_pr).to receive(:octo).and_return(@octo_obj) + end + + let(:pr_obj) do + { + user: { login: 'theckman' }, state: 'closed', merged: true, pr_sha: '1234567890' + } + end + let(:info) { { pr_sha: '1234567890' } } + + it 'should return an instance of Hash' do + expect(github_pr.send(:build_pr_status!, info, pr_obj, full_name)) + .to be_an_instance_of Hash + end + + it 'should call octo.user' do + expect(@octo_obj).to receive(:user).with('theckman') + github_pr.send(:build_pr_status!, info, pr_obj, full_name) + end + + it 'should call octo.combined_status and set it to :build_status' do + expect(@octo_obj).to receive(:combined_status) + .with(full_name, '1234567890') + .and_return(@cs_obj) + github_pr.send(:build_pr_status!, info, pr_obj, full_name) + expect(info[:build_status]).to eql 'success' + end + + context 'when user has a name set' do + it 'should include the name' do + github_pr.send(:build_pr_status!, info, pr_obj, full_name) + expect(info[:user]).to eql 'theckman (Tim Heckman)' + end + end + + context 'when the PR has been merged' do + it 'should set the :state key to :merged' do + github_pr.send(:build_pr_status!, info, pr_obj, full_name) + expect(info[:state]).to eql :merged + end + + it 'should set the :state_str to "Merged"' do + github_pr.send(:build_pr_status!, info, pr_obj, full_name) + expect(info[:state_str]).to eql 'Merged' + end + end + + context 'when user has no name set' do + before do + @octo_obj = double('Octokit::Client', user: {}, combined_status: @cs_obj) + allow(github_pr).to receive(:octo).and_return(@octo_obj) + end + + it 'should not include the real name parenthesis' do + github_pr.send(:build_pr_status!, info, pr_obj, full_name) + expect(info[:user]).to eql 'theckman' + end + end + + context 'when PR not merged' do + context 'when status is open' do + let(:pr_obj) do + { + user: { login: 'theckman' }, state: 'open', merged: false + } + end + + it 'should set the :state key to :open' do + github_pr.send(:build_pr_status!, info, pr_obj, full_name) + expect(info[:state]).to eql :open + end + + it 'should set the :state_str to "Open"' do + github_pr.send(:build_pr_status!, info, pr_obj, full_name) + expect(info[:state_str]).to eql 'Open' + end + end + + context 'when status is closed' do + let(:pr_obj) do + { + user: { login: 'theckman' }, state: 'closed', merged: false + } + end + + it 'should set the :state key to :closed' do + github_pr.send(:build_pr_status!, info, pr_obj, full_name) + expect(info[:state]).to eql :closed + end + + it 'should set the :state_str to "Closed"' do + github_pr.send(:build_pr_status!, info, pr_obj, full_name) + expect(info[:state_str]).to eql 'Closed' + end + end + end + end + + describe '.build_pr_merge!' do + before do + @user_obj = { name: 'Tim Heckman' } + @octo_obj = double('Octokit::Client', user: @user_obj) + allow(github_pr).to receive(:octo).and_return(@octo_obj) + end + + let(:pr_obj) do + { + state: :open, mergeable: true + } + end + let(:info) { { state: :open } } + + it 'should return an instance of Hash' do + expect(github_pr.send(:build_pr_merge!, info, pr_obj)) + .to be_an_instance_of Hash + end + + it 'should set the :mergable key' do + github_pr.send(:build_pr_merge!, info, pr_obj) + expect(info[:mergeable]).to eql true + end + + context 'when not merged' do + it 'should not set the :merged_by key' do + github_pr.send(:build_pr_merge!, info, pr_obj) + expect(info.key?(:merged_by)).to be_falsey + end + end + + context 'when merged' do + let(:pr_obj) do + { + state: :merged, mergeable: nil, merged_by: { login: 'theckman' } + } + end + let(:info) { { state: :merged } } + + it 'should grab some user info about who merged' do + expect(@octo_obj).to receive(:user).with('theckman').and_return(@user_obj) + github_pr.send(:build_pr_merge!, info, pr_obj) + end + + context 'when user has a name field' do + it 'should set the :merged_by key' do + github_pr.send(:build_pr_merge!, info, pr_obj) + expect(info[:merged_by]).to eql 'theckman (Tim Heckman)' + end + end + + context 'when the user has no name field' do + before do + @user_obj = {} + @octo_obj = double('Octokit::Client', user: @user_obj) + allow(github_pr).to receive(:octo).and_return(@octo_obj) + end + + it 'should set the :merged_by key without parenthesis' do + github_pr.send(:build_pr_merge!, info, pr_obj) + expect(info[:merged_by]).to eql 'theckman' + end + end + end + end + + describe '.build_pr_comments!' do + let(:pr_obj) { { comments: 1, review_comments: 3 } } + let(:info) { {} } + + it 'should return a Hash' do + expect(github_pr.send(:build_pr_comments!, info, pr_obj)).to be_an_instance_of Hash + end + + it 'should set the :comments key' do + github_pr.send(:build_pr_comments!, info, pr_obj) + expect(info[:comments]).to eql 1 + end + + it 'should set the :review_comments key' do + github_pr.send(:build_pr_comments!, info, pr_obj) + expect(info[:review_comments]).to eql 3 + end + end + + describe '.build_pr_info' do + before do + allow(github_pr).to receive(:build_pr_header!).and_return(nil) + allow(github_pr).to receive(:build_pr_commitinfo!).and_return(nil) + allow(github_pr).to receive(:build_pr_status!).and_return(nil) + allow(github_pr).to receive(:build_pr_merge!).and_return(nil) + allow(github_pr).to receive(:build_pr_comments!).and_return(nil) + end + + let(:pr_obj) { :ohai } + + it 'should return an instance of Hash' do + expect(github_pr.send(:build_pr_info, pr_obj, full_name)).to be_an_instance_of Hash + end + + it 'should call .build_pr_header!' do + expect(github_pr).to receive(:build_pr_header!).with({}, pr_obj).and_return(nil) + github_pr.send(:build_pr_info, pr_obj, full_name) + end + + it 'should call .build_pr_commitinfo!' do + expect(github_pr).to receive(:build_pr_commitinfo!).with({}, pr_obj).and_return(nil) + github_pr.send(:build_pr_info, pr_obj, full_name) + end + + it 'should call .build_pr_status!' do + expect(github_pr).to receive(:build_pr_status!).with({}, pr_obj, full_name).and_return(nil) + github_pr.send(:build_pr_info, pr_obj, full_name) + end + + it 'should call .build_pr_merge!' do + expect(github_pr).to receive(:build_pr_merge!).with({}, pr_obj).and_return(nil) + github_pr.send(:build_pr_info, pr_obj, full_name) + end + + it 'should call .build_pr_comments!' do + expect(github_pr).to receive(:build_pr_comments!).with({}, pr_obj).and_return(nil) + github_pr.send(:build_pr_info, pr_obj, full_name) + end + end + + #### + # Handlers + #### + describe '.merge_pr' do + before do @merge_status = { sha: 'abc456', merged: true, message: 'Pull Request successfully merged' } @octo_obj = double('Octokit::Client', merge_pull_request: @merge_status) allow(github_pr).to receive(:octo).and_return(@octo_obj) end @@ -47,10 +396,79 @@ .to be_nil end end end + describe '.pr_info' do + context 'when PR is not merged' do + before do + @pr_info = { + title: 'Test Pull Request (Not Real)', number: 42, + url: "https://github.com/#{github_org}/#{github_repo}/pulls/42", + commits: 1, plus: 42, minus: 0, changed_files: 1, pr_sha: '1234567890', + base_sha: '0987654321', pr_sha_short: '1234567', user: 'theckman (Tim Heckman)', + state: :open, state_str: 'Open', build_status: 'success', mergeable: true, + review_comments: 2, comments: 1 + } + @pr_resp = { fail: false, not_found: false, pr: @pr_info } + allow(github_pr).to receive(:pull_request).and_return(@pr_resp) + allow(github_pr).to receive(:build_pr_info).and_return(@pr_info) + end + + it 'should reply with the expeced output' do + r = 'GrapeDuty/lita-test #42: Test Pull Request (Not Real) :: ' \ + "https://github.com/GrapeDuty/lita-test/pulls/42\n" \ + "Opened By: theckman (Tim Heckman) | State: Open | Build: success | Mergeable: true\n" \ + 'Head: 1234567 | Commits: 1 (+42/-0) :: ' \ + "https://github.com/GrapeDuty/lita-test/compare/0987654321...1234567890\n" \ + "PR Comments: 1 | Code Comments: 2\n" + send_command("gh pr info #42 #{github_org}/#{github_repo}") + expect(replies.last).to eql r + end + end + + context 'when the PR has been merged' do + before do + @pr_info = { + title: 'Test Pull Request (Not Real)', number: 42, + url: "https://github.com/#{github_org}/#{github_repo}/pulls/42", + commits: 1, plus: 42, minus: 0, changed_files: 1, pr_sha: '1234567890', + base_sha: '0987654321', pr_sha_short: '1234567', user: 'theckman (Tim Heckman)', + state: :merged, state_str: 'Merged', build_status: 'success', mergeable: true, + merged_by: 'theckman (Tim Heckman)', review_comments: 2, comments: 1 + } + @pr_resp = { fail: false, not_found: false, pr: @pr_info } + allow(github_pr).to receive(:pull_request).and_return(@pr_resp) + allow(github_pr).to receive(:build_pr_info).and_return(@pr_info) + end + + it 'should reply with the expeced output' do + r = 'GrapeDuty/lita-test #42: Test Pull Request (Not Real) :: ' \ + "https://github.com/GrapeDuty/lita-test/pulls/42\n" \ + 'Opened By: theckman (Tim Heckman) | State: Merged | Build: success | ' \ + "Merged By: theckman (Tim Heckman)\n" \ + 'Head: 1234567 | Commits: 1 (+42/-0) :: ' \ + "https://github.com/GrapeDuty/lita-test/compare/0987654321...1234567890\n" \ + "PR Comments: 1 | Code Comments: 2\n" + send_command("gh pr info #42 #{github_org}/#{github_repo}") + expect(replies.last).to eql r + end + end + + context 'when the PR was not found' do + before do + @pr_resp = { fail: true, not_found: true, pr: @pr_info } + allow(github_pr).to receive(:pull_request).and_return(@pr_resp) + end + + it 'should reply with the not found error' do + send_command("gh pr info #42 #{github_org}/#{github_repo}") + expect(replies.last).to eql 'Pull request #42 on GrapeDuty/lita-test not found' + end + end + end + describe '.pr_merge' do before do @cfg_obj = double('Lita::Configuration', pr_merge_enabled: true) @pr_obj = { head: { ref: 'fix-some-bugs' }, title: 'fix bug' } @merge_status = { sha: 'abc456', merged: true, message: 'Pull Request successfully merged' } @@ -64,10 +482,10 @@ context 'when command disabled' do before do allow(github_pr).to receive(:func_disabled?).and_return(true) end - it 'should no-op and say such if the command is disabled' do + it 'should no-op and say such' do send_command("shipit #42 #{github_org}/#{github_repo}") expect(replies.last).to eql disabled_reply end end