From b96744c6bb37fe3e17321aef18fa1d719f586f85 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 17 Jul 2020 17:54:48 -0500 Subject: [PATCH] Support error_code returned by specific API endpoints An error response may contain useful additional context, and this allows users to access that context on the exception class. For example, the cherry-pick API now includes an error_code field to indicate why the cherry-pick failed, which can now be accessed via `ResponseError#error_code`. --- lib/gitlab/error.rb | 11 +++++ spec/fixtures/cherry_pick_commit_failure.json | 1 + spec/gitlab/client/commits_spec.rb | 40 ++++++++++++------- spec/gitlab/error_spec.rb | 35 ++++++++++++++++ 4 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 spec/fixtures/cherry_pick_commit_failure.json diff --git a/lib/gitlab/error.rb b/lib/gitlab/error.rb index a37ccbeaf..25f559419 100644 --- a/lib/gitlab/error.rb +++ b/lib/gitlab/error.rb @@ -34,6 +34,17 @@ def response_message @response.parsed_response.message end + # Additional error context returned by some API endpoints + # + # @return [String] + def error_code + if @response.respond_to?(:error_code) + @response.error_code + else + '' + end + end + private # Human friendly message. diff --git a/spec/fixtures/cherry_pick_commit_failure.json b/spec/fixtures/cherry_pick_commit_failure.json new file mode 100644 index 000000000..a1f265d68 --- /dev/null +++ b/spec/fixtures/cherry_pick_commit_failure.json @@ -0,0 +1 @@ +{"message":"Sorry, we cannot cherry-pick this commit automatically. This commit may already have been cherry-picked, or a more recent commit may have updated some of its content.","error_code":"conflict"} diff --git a/spec/gitlab/client/commits_spec.rb b/spec/gitlab/client/commits_spec.rb index 3512513fa..4de8449f9 100644 --- a/spec/gitlab/client/commits_spec.rb +++ b/spec/gitlab/client/commits_spec.rb @@ -65,20 +65,32 @@ end describe '.cherry_pick_commit' do - before do - stub_post('/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/cherry_pick', 'project_commit').with(body: { branch: 'master' }) - @cherry_pick_commit = Gitlab.cherry_pick_commit(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6', 'master') - end - - it 'gets the correct resource' do - expect(a_post('/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/cherry_pick') - .with(body: { branch: 'master' })) - .to have_been_made - end - - it 'returns the correct response' do - expect(@cherry_pick_commit).to be_a Gitlab::ObjectifiedHash - expect(@cherry_pick_commit.id).to eq('6104942438c14ec7bd21c6cd5bd995272b3faff6') + context 'on success' do + before do + stub_post('/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/cherry_pick', 'project_commit').with(body: { branch: 'master' }) + @cherry_pick_commit = Gitlab.cherry_pick_commit(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6', 'master') + end + + it 'gets the correct resource' do + expect(a_post('/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/cherry_pick') + .with(body: { branch: 'master' })) + .to have_been_made + end + + it 'returns the correct response' do + expect(@cherry_pick_commit).to be_a Gitlab::ObjectifiedHash + expect(@cherry_pick_commit.id).to eq('6104942438c14ec7bd21c6cd5bd995272b3faff6') + end + end + + context 'on failure' do + it 'includes the error_code' do + stub_post('/projects/3/repository/commits/6104942438c14ec7bd21c6cd5bd995272b3faff6/cherry_pick', 'cherry_pick_commit_failure', 400) + + expect { Gitlab.cherry_pick_commit(3, '6104942438c14ec7bd21c6cd5bd995272b3faff6', 'master') }.to raise_error(Gitlab::Error::BadRequest) do |ex| + expect(ex.error_code).to eq('conflict') + end + end end end diff --git a/spec/gitlab/error_spec.rb b/spec/gitlab/error_spec.rb index 7fdc12ea6..cf16f906f 100644 --- a/spec/gitlab/error_spec.rb +++ b/spec/gitlab/error_spec.rb @@ -68,4 +68,39 @@ expect(described_class.new(response_double).send(:build_error_message)).to match(/Retry text/) end end + + describe '#error_code' do + it 'returns the value when available' do + headers = { 'content-type' => 'application/json' } + response_double = double( + 'response', + body: 'Retry later', + to_s: 'Retry text', + parsed_response: { message: 'Retry hash' }, + code: 400, + error_code: 'conflict', + options: {}, + headers: headers, + request: @request_double + ) + + expect(described_class.new(response_double).error_code).to eq 'conflict' + end + + it 'returns nothing when unavailable' do + headers = { 'content-type' => 'application/json' } + response_double = double( + 'response', + body: 'Retry later', + to_s: 'Retry text', + parsed_response: { message: 'Retry hash' }, + code: 400, + options: {}, + headers: headers, + request: @request_double + ) + + expect(described_class.new(response_double).error_code).to eq '' + end + end end