diff --git a/ee/changelogs/unreleased/jira-dvcs-merge-requests.yml b/ee/changelogs/unreleased/jira-dvcs-merge-requests.yml new file mode 100644 index 0000000000000000000000000000000000000000..a403b49d2114b54495a33d1dcbd1e1429192cd11 --- /dev/null +++ b/ee/changelogs/unreleased/jira-dvcs-merge-requests.yml @@ -0,0 +1,5 @@ +--- +title: Fix merge requests being added to Jira Development Panel +merge_request: 10342 +author: +type: fixed diff --git a/ee/lib/api/github/entities.rb b/ee/lib/api/github/entities.rb index 58966273cea6240b28c2060a091f7ed3cca8fe51..58ccc0265fc2532a1ac8137da513981c0ec3c622 100644 --- a/ee/lib/api/github/entities.rb +++ b/ee/lib/api/github/entities.rb @@ -170,6 +170,38 @@ class PullRequest < Grape::Entity expose :target_project, as: :repo, using: Repository end end + + class PullRequestPayload < Grape::Entity + expose :action do |merge_request| + case merge_request.state + when 'merged', 'closed' + 'closed' + else + 'opened' + end + end + + expose :id + expose :pull_request, using: PullRequest do |merge_request| + merge_request + end + end + + class PullRequestEvent < Grape::Entity + expose :id do |merge_request| + updated_at = merge_request.updated_at.to_i + "#{merge_request.id}-#{updated_at}" + end + expose :type do |_merge_request| + 'PullRequestEvent' + end + expose :updated_at, as: :created_at + expose :payload, using: PullRequestPayload do |merge_request| + # The merge request data is used by PullRequestPayload and PullRequest, so we just provide it + # here. Otherwise Grape::Entity would try to access a field "payload" on Merge Request. + merge_request + end + end end end end diff --git a/ee/lib/api/v3/github.rb b/ee/lib/api/v3/github.rb index 3975c96ae5944d49ce323cd437fbd41bb1319e9f..a69aae7b3b934c525360489ee6beebcaeaa03b72 100644 --- a/ee/lib/api/v3/github.rb +++ b/ee/lib/api/v3/github.rb @@ -131,6 +131,10 @@ def licensed_project?(project) present find_merge_requests, with: ::API::Github::Entities::PullRequest end + get '/-/jira/events' do + present [] + end + params do use :project_full_path end @@ -142,6 +146,15 @@ def licensed_project?(project) present paginate(merge_requests), with: ::API::Github::Entities::PullRequest end + params do + use :project_full_path + end + get ':namespace/:project/pulls/:id', requirements: PROJECT_ENDPOINT_REQUIREMENTS do + mr = find_merge_request_with_access(params[:id]) + + present mr, with: ::API::Github::Entities::PullRequest + end + # In Github, each Merge Request is automatically also an issue. # Therefore we return its comments here. # It'll present _just_ the comments counting with a link to GitLab on @@ -166,10 +179,12 @@ def licensed_project?(project) # Self-hosted Jira (tested on 7.11.1) requests this endpoint right # after fetching branches. - # We need to respond with a 200 request to avoid breaking the - # integration flow (fetching merge requests). get ':namespace/:project/events' do - present [] + user_project = find_project_with_access(params) + + merge_requests = MergeRequestsFinder.new(current_user, authorized_only: true, project_id: user_project.id).execute + + present paginate(merge_requests), with: ::API::Github::Entities::PullRequestEvent end params do diff --git a/ee/spec/fixtures/api/schemas/entities/github/pull_request.json b/ee/spec/fixtures/api/schemas/entities/github/pull_request.json new file mode 100644 index 0000000000000000000000000000000000000000..dfcddd2eeccca066de8e07fe786f1510bc77cee9 --- /dev/null +++ b/ee/spec/fixtures/api/schemas/entities/github/pull_request.json @@ -0,0 +1,142 @@ +{ + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "body": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "integer" + }, + "number": { + "type": "integer" + }, + "state": { + "type": "string" + }, + "html_url": { + "type": "string" + }, + "merged": { + "type": "boolean" + }, + "merged_at": { + "type": [ + "date", + "null" + ] + }, + "closed_at": { + "type": [ + "date", + "null" + ] + }, + "updated_at": { + "type": "date" + }, + "assignee": { + "type": "object", + "required": [ + "id", + "login", + "url" + ], + "properties": { + "id": { + "type": "integer" + }, + "login": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "author": { + "type": "object", + "required": [ + "id", + "login", + "url" + ], + "properties": { + "id": { + "type": "integer" + }, + "login": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "head": { + "type": "object", + "required": [ + "label", + "ref", + "repo" + ], + "properties": { + "label": { + "type": "string" + }, + "ref": { + "type": "string" + }, + "repo": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "repository.json" + } + ] + } + }, + "additionalProperties": false + }, + "base": { + "type": "object", + "required": [ + "label", + "ref", + "repo" + ], + "properties": { + "label": { + "type": "string" + }, + "ref": { + "type": "string" + }, + "repo": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "repository.json" + } + ] + } + }, + "additionalProperties": false + }, + "additionalProperties": false + } +} \ No newline at end of file diff --git a/ee/spec/requests/api/v3/github_spec.rb b/ee/spec/requests/api/v3/github_spec.rb index 1fc0f0560447a261eff042677b6cee7bda5fa5f7..403c2748c8ae750ef25369eb21523b23dca71c74 100644 --- a/ee/spec/requests/api/v3/github_spec.rb +++ b/ee/spec/requests/api/v3/github_spec.rb @@ -39,15 +39,6 @@ end shared_examples_for 'Jira-specific mimicked GitHub endpoints' do - describe 'GET /repos/.../events' do - it 'returns an empty array' do - jira_get v3_api("/repos/#{path}/events", user) - - expect(response).to have_gitlab_http_status(200) - expect(json_response).to eq([]) - end - end - describe 'GET /.../issues/:id/comments' do context 'when user has access to the merge request' do let(:merge_request) do @@ -116,12 +107,70 @@ it_behaves_like 'Jira-specific mimicked GitHub endpoints' do let(:path) { '-/jira' } end + + it 'returns an empty Array for events' do + jira_get v3_api("/repos/-/jira/events", user) + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to eq([]) + end end context 'new :namespace/:project jira endpoints' do it_behaves_like 'Jira-specific mimicked GitHub endpoints' do let(:path) { "#{project.namespace.path}/#{project.path}" } end + + describe 'GET events' do + let(:group) { create(:group) } + let(:project) { create(:project, :empty_repo, group: group) } + let(:events_path) { "/repos/#{group.path}/#{project.path}/events" } + + before do + stub_licensed_features(jira_dev_panel_integration: true) + end + + context 'if there are no merge requests' do + it 'returns an empty array' do + jira_get v3_api(events_path, user) + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to eq([]) + end + end + + context 'if there is a merge request' do + let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) } + + it 'returns an event' do + jira_get v3_api(events_path, user) + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to be_an(Array) + expect(json_response.size).to eq(1) + end + end + + context 'if there are more merge requests' do + let!(:merge_request) { create(:merge_request, id: 10000, source_project: project, target_project: project, author: user) } + let!(:merge_request2) { create(:merge_request, id: 10001, source_project: project, source_branch: generate(:branch), target_project: project, author: user) } + + it 'returns the expected amount of events' do + jira_get v3_api(events_path, user) + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to be_an(Array) + expect(json_response.size).to eq(2) + end + + it 'ensures each event has a unique id' do + jira_get v3_api(events_path, user) + + ids = json_response.map { |event| event['id'] }.uniq + expect(ids.size).to eq(2) + end + end + end end describe 'repo pulls' do @@ -158,6 +207,17 @@ expect(response).to match_response_schema('entities/github/pull_requests', dir: 'ee') end end + + describe 'GET /repos/:namespace/:project/pulls/:id' do + it 'returns the requested merge request in github format' do + stub_licensed_features(jira_dev_panel_integration: true) + + jira_get v3_api("/repos/#{project.namespace.path}/#{project.path}/pulls/#{merge_request.id}", user) + + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('entities/github/pull_request', dir: 'ee') + end + end end describe 'GET /users/:namespace/repos' do