Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.rb « v3 « api « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 29e4a79110f5884018f3bedd2a68063859c23247 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# frozen_string_literal: true

# These endpoints partially mimic Github API behavior in order to successfully
# integrate with Jira Development Panel.
# Endpoints returning an empty list were temporarily added to avoid 404's
# during Jira's DVCS integration.
#
module API
  module V3
    class Github < ::API::Base
      NO_SLASH_URL_PART_REGEX = %r{[^/]+}.freeze
      ENDPOINT_REQUIREMENTS = {
        namespace: NO_SLASH_URL_PART_REGEX,
        project: NO_SLASH_URL_PART_REGEX,
        username: NO_SLASH_URL_PART_REGEX
      }.freeze

      # Used to differentiate Jira Cloud requests from Jira Server requests
      # Jira Cloud user agent format: Jira DVCS Connector Vertigo/version
      # Jira Server user agent format: Jira DVCS Connector/version
      JIRA_DVCS_CLOUD_USER_AGENT = 'Jira DVCS Connector Vertigo'

      include PaginationParams

      feature_category :integrations

      before do
        authorize_jira_user_agent!(request)
        authenticate!
      end

      helpers do
        params :project_full_path do
          requires :namespace, type: String
          requires :project, type: String
        end

        def authorize_jira_user_agent!(request)
          not_found! unless Gitlab::Jira::Middleware.jira_dvcs_connector?(request.env)
        end

        def update_project_feature_usage_for(project)
          # Prevent errors on GitLab Geo not allowing
          # UPDATE statements to happen in GET requests.
          return if Gitlab::Database.read_only?

          project.log_jira_dvcs_integration_usage(cloud: jira_cloud?)
        end

        def jira_cloud?
          request.env['HTTP_USER_AGENT'].include?(JIRA_DVCS_CLOUD_USER_AGENT)
        end

        def find_project_with_access(params)
          project = find_project!(
            ::Gitlab::Jira::Dvcs.restore_full_path(**params.slice(:namespace, :project).symbolize_keys)
          )
          not_found! unless can?(current_user, :download_code, project)
          project
        end

        # rubocop: disable CodeReuse/ActiveRecord
        def find_merge_requests
          merge_requests = authorized_merge_requests.reorder(updated_at: :desc)
          paginate(merge_requests)
        end
        # rubocop: enable CodeReuse/ActiveRecord

        # rubocop: disable CodeReuse/ActiveRecord
        def find_merge_request_with_access(id, access_level = :read_merge_request)
          merge_request = authorized_merge_requests.find_by(id: id)
          not_found! unless can?(current_user, access_level, merge_request)
          merge_request
        end
        # rubocop: enable CodeReuse/ActiveRecord

        def authorized_merge_requests
          MergeRequestsFinder.new(current_user, authorized_only: !current_user.admin?)
            .execute.with_jira_integration_associations
        end

        def authorized_merge_requests_for_project(project)
          MergeRequestsFinder
            .new(current_user, authorized_only: !current_user.admin?, project_id: project.id)
            .execute.with_jira_integration_associations
        end

        # rubocop: disable CodeReuse/ActiveRecord
        def find_notes(noteable)
          # They're not presented on Jira Dev Panel ATM. A comments count with a
          # redirect link is presented.
          notes = paginate(noteable.notes.user.reorder(nil))
          notes.select { |n| n.readable_by?(current_user) }
        end
        # rubocop: enable CodeReuse/ActiveRecord
      end

      resource :orgs do
        get ':namespace/repos' do
          present []
        end
      end

      resource :user do
        get :repos do
          present []
        end
      end

      resource :users do
        params do
          use :pagination
        end

        get ':namespace/repos' do
          namespace = Namespace.find_by_full_path(params[:namespace])
          not_found!('Namespace') unless namespace

          projects = current_user.can_read_all_resources? ? Project.all : current_user.authorized_projects
          projects = projects.in_namespace(namespace.self_and_descendants)

          projects_cte = Project.wrap_with_cte(projects)
                                .eager_load_namespace_and_owner
                                .with_route

          present paginate(projects_cte),
                  with: ::API::Github::Entities::Repository,
                  root_namespace: namespace.root_ancestor
        end

        get ':username' do
          forbidden! unless can?(current_user, :read_users_list)
          user = UsersFinder.new(current_user, { username: params[:username] }).execute.first
          not_found! unless user
          present user, with: ::API::Github::Entities::User
        end
      end

      # Jira dev panel integration weirdly requests for "/-/jira/pulls" instead
      # "/api/v3/repos/<namespace>/<project>/pulls". This forces us into
      # returning _all_ Merge Requests from authorized projects (user is a member),
      # instead just the authorized MRs from a project.
      # Jira handles the filtering, presenting just MRs mentioning the Jira
      # issue ID on the MR title / description.
      resource :repos do
        # Keeping for backwards compatibility with old Jira integration instructions
        # so that users that do not change it will not suddenly have a broken integration
        get '/-/jira/pulls' do
          present find_merge_requests, with: ::API::Github::Entities::PullRequest
        end

        get '/-/jira/events' do
          present []
        end

        params do
          use :project_full_path
        end
        get ':namespace/:project/pulls' do
          user_project = find_project_with_access(params)

          merge_requests = authorized_merge_requests_for_project(user_project)

          present paginate(merge_requests), with: ::API::Github::Entities::PullRequest
        end

        params do
          use :project_full_path
        end
        get ':namespace/:project/pulls/:id' do
          merge_request = find_merge_request_with_access(params[:id])

          present merge_request, 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
        # Jira dev panel, not the actual note content.
        get ':namespace/:project/issues/:id/comments' do
          merge_request = find_merge_request_with_access(params[:id])

          present find_notes(merge_request), with: ::API::Github::Entities::NoteableComment
        end

        # This refer to "review" comments but Jira dev panel doesn't seem to
        # present it accordingly.
        get ':namespace/:project/pulls/:id/comments' do
          present []
        end

        # Commits are not presented within "Pull Requests" modal on Jira dev
        # panel.
        get ':namespace/:project/pulls/:id/commits' do
          present []
        end

        # Self-hosted Jira (tested on 7.11.1) requests this endpoint right
        # after fetching branches.
        get ':namespace/:project/events' do
          user_project = find_project_with_access(params)

          merge_requests = authorized_merge_requests_for_project(user_project)

          present paginate(merge_requests), with: ::API::Github::Entities::PullRequestEvent
        end

        params do
          use :project_full_path
          use :pagination
        end
        get ':namespace/:project/branches' do
          user_project = find_project_with_access(params)

          update_project_feature_usage_for(user_project)

          branches = ::Kaminari.paginate_array(user_project.repository.branches.sort_by(&:name))

          present paginate(branches), with: ::API::Github::Entities::Branch, project: user_project
        end

        params do
          use :project_full_path
        end
        get ':namespace/:project/commits/:sha' do
          user_project = find_project_with_access(params)

          commit = user_project.commit(params[:sha])

          not_found! 'Commit' unless commit

          present commit, with: ::API::Github::Entities::RepoCommit
        end
      end
    end
  end
end