diff options
Diffstat (limited to 'lib/api')
-rw-r--r-- | lib/api/commits.rb | 11 | ||||
-rw-r--r-- | lib/api/entities.rb | 12 | ||||
-rw-r--r-- | lib/api/environments.rb | 8 | ||||
-rw-r--r-- | lib/api/helpers.rb | 4 | ||||
-rw-r--r-- | lib/api/helpers/graphql_helpers.rb | 22 | ||||
-rw-r--r-- | lib/api/helpers/notes_helpers.rb | 14 | ||||
-rw-r--r-- | lib/api/helpers/pagination.rb | 2 | ||||
-rw-r--r-- | lib/api/issues.rb | 6 | ||||
-rw-r--r-- | lib/api/job_artifacts.rb | 16 | ||||
-rw-r--r-- | lib/api/merge_requests.rb | 8 | ||||
-rw-r--r-- | lib/api/projects.rb | 39 | ||||
-rw-r--r-- | lib/api/release/links.rb | 2 | ||||
-rw-r--r-- | lib/api/runners.rb | 6 | ||||
-rw-r--r-- | lib/api/snippets.rb | 25 | ||||
-rw-r--r-- | lib/api/todos.rb | 32 | ||||
-rw-r--r-- | lib/api/validations/types/labels_list.rb | 24 | ||||
-rw-r--r-- | lib/api/version.rb | 18 |
17 files changed, 186 insertions, 63 deletions
diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 8defc59224d..65eb9bfb87e 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -99,6 +99,7 @@ module API optional :author_email, type: String, desc: 'Author email for commit' optional :author_name, type: String, desc: 'Author name for commit' optional :stats, type: Boolean, default: true, desc: 'Include commit stats' + optional :force, type: Boolean, default: false, desc: 'When `true` overwrites the target branch with a new commit based on the `start_branch`' end post ':id/repository/commits' do authorize_push_to_branch!(params[:branch]) @@ -318,10 +319,18 @@ module API use :pagination end get ':id/repository/commits/:sha/merge_requests', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do + authorize! :read_merge_request, user_project + commit = user_project.commit(params[:sha]) not_found! 'Commit' unless commit - present paginate(commit.merge_requests), with: Entities::MergeRequestBasic + commit_merge_requests = MergeRequestsFinder.new( + current_user, + project_id: user_project.id, + commit_sha: commit.sha + ).execute + + present paginate(commit_merge_requests), with: Entities::MergeRequestBasic end desc "Get a commit's GPG signature" do diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 18f15632f2b..2cd0d93b205 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -156,7 +156,7 @@ module API class BasicProjectDetails < ProjectIdentity include ::API::ProjectsRelationBuilder - expose :default_branch + expose :default_branch, if: -> (project, options) { Ability.allowed?(options[:current_user], :download_code, project) } # Avoids an N+1 query: https://github.com/mbleigh/acts-as-taggable-on/issues/91#issuecomment-168273770 expose :tag_list do |project| # project.tags.order(:name).pluck(:name) is the most suitable option @@ -261,7 +261,7 @@ module API expose :open_issues_count, if: lambda { |project, options| project.feature_available?(:issues, options[:current_user]) } expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] } expose :public_builds, as: :public_jobs - expose :ci_config_path + expose :ci_config_path, if: -> (project, options) { Ability.allowed?(options[:current_user], :download_code, project) } expose :shared_with_groups do |project, options| SharedGroup.represent(project.project_group_links, options) end @@ -270,8 +270,9 @@ module API expose :only_allow_merge_if_all_discussions_are_resolved expose :printing_merge_request_link_enabled expose :merge_method - - expose :statistics, using: 'API::Entities::ProjectStatistics', if: :statistics + expose :statistics, using: 'API::Entities::ProjectStatistics', if: -> (project, options) { + options[:statistics] && Ability.allowed?(options[:current_user], :download_code, project) + } # rubocop: disable CodeReuse/ActiveRecord def self.preload_relation(projects_relation, options = {}) @@ -882,7 +883,8 @@ module API expose :target_type expose :target do |todo, options| - todo_target_class(todo.target_type).represent(todo.target, options) + todo_options = options.fetch(todo.target_type, {}) + todo_target_class(todo.target_type).represent(todo.target, todo_options) end expose :target_url do |todo, options| diff --git a/lib/api/environments.rb b/lib/api/environments.rb index 0278c6c54a5..5b0f3b914cb 100644 --- a/lib/api/environments.rb +++ b/lib/api/environments.rb @@ -22,7 +22,7 @@ module API get ':id/environments' do authorize! :read_environment, user_project - present paginate(user_project.environments), with: Entities::Environment + present paginate(user_project.environments), with: Entities::Environment, current_user: current_user end desc 'Creates a new environment' do @@ -40,7 +40,7 @@ module API environment = user_project.environments.create(declared_params) if environment.persisted? - present environment, with: Entities::Environment + present environment, with: Entities::Environment, current_user: current_user else render_validation_error!(environment) end @@ -63,7 +63,7 @@ module API update_params = declared_params(include_missing: false).extract!(:name, :external_url) if environment.update(update_params) - present environment, with: Entities::Environment + present environment, with: Entities::Environment, current_user: current_user else render_validation_error!(environment) end @@ -99,7 +99,7 @@ module API environment.stop_with_action!(current_user) status 200 - present environment, with: Entities::Environment + present environment, with: Entities::Environment, current_user: current_user end end end diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 54cd4cd9cdb..825fab62034 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -244,6 +244,10 @@ module API authorize! :read_build, user_project end + def authorize_destroy_artifacts! + authorize! :destroy_artifacts, user_project + end + def authorize_update_builds! authorize! :update_build, user_project end diff --git a/lib/api/helpers/graphql_helpers.rb b/lib/api/helpers/graphql_helpers.rb new file mode 100644 index 00000000000..94010ab1bc2 --- /dev/null +++ b/lib/api/helpers/graphql_helpers.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module API + module Helpers + # GraphqlHelpers is used by the REST API when it is acting like a client + # against the graphql API. Helper code for the graphql server implementation + # should be in app/graphql/ or lib/gitlab/graphql/ + module GraphqlHelpers + def conditionally_graphql!(fallback:, query:, context: {}, transform: nil) + return fallback.call unless Feature.enabled?(:graphql) + + result = GitlabSchema.execute(query, context: context) + + if transform + transform.call(result) + else + result + end + end + end + end +end diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb index 216b2c45741..795dca5cf03 100644 --- a/lib/api/helpers/notes_helpers.rb +++ b/lib/api/helpers/notes_helpers.rb @@ -70,14 +70,7 @@ module API def find_noteable(parent, noteables_str, noteable_id) noteable = public_send("find_#{parent}_#{noteables_str.singularize}", noteable_id) # rubocop:disable GitlabSecurity/PublicSend - readable = - if noteable.is_a?(Commit) - # for commits there is not :read_commit policy, check if user - # has :read_note permission on the commit's project - can?(current_user, :read_note, user_project) - else - can?(current_user, noteable_read_ability_name(noteable), noteable) - end + readable = can?(current_user, noteable_read_ability_name(noteable), noteable) return not_found!(noteables_str) unless readable @@ -89,12 +82,11 @@ module API end def create_note(noteable, opts) - policy_object = noteable.is_a?(Commit) ? user_project : noteable - authorize!(:create_note, policy_object) + authorize!(:create_note, noteable) parent = noteable_parent(noteable) - opts.delete(:created_at) unless current_user.can?(:set_note_created_at, policy_object) + opts.delete(:created_at) unless current_user.can?(:set_note_created_at, noteable) opts[:updated_at] = opts[:created_at] if opts[:created_at] diff --git a/lib/api/helpers/pagination.rb b/lib/api/helpers/pagination.rb index d00e61678b5..94b58a64d26 100644 --- a/lib/api/helpers/pagination.rb +++ b/lib/api/helpers/pagination.rb @@ -149,7 +149,7 @@ module API def conditions(pagination) fields = pagination.fields - return nil if fields.empty? + return if fields.empty? placeholder = fields.map { '?' } diff --git a/lib/api/issues.rb b/lib/api/issues.rb index f43f4d961d6..b2ec4ed898e 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -28,13 +28,13 @@ module API args[:scope] = args[:scope].underscore if args[:scope] issues = IssuesFinder.new(current_user, args).execute - .preload(:assignees, :labels, :notes, :timelogs, :project, :author, :closed_by) + .with_api_entity_associations issues.reorder(order_options_with_tie_breaker) end # rubocop: enable CodeReuse/ActiveRecord params :issues_params do - optional :labels, type: String, desc: 'Comma-separated list of label names' + optional :labels, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names' optional :milestone, type: String, desc: 'Milestone title' optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at', desc: 'Return issues ordered by `created_at` or `updated_at` fields.' @@ -65,7 +65,7 @@ module API optional :assignee_ids, type: Array[Integer], desc: 'The array of user IDs to assign issue' optional :assignee_id, type: Integer, desc: '[Deprecated] The ID of a user to assign issue' optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign issue' - optional :labels, type: String, desc: 'Comma-separated list of label names' + optional :labels, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names' optional :due_date, type: String, desc: 'Date string in the format YEAR-MONTH-DAY' optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential' optional :discussion_locked, type: Boolean, desc: " Boolean parameter indicating if the issue's discussion is locked" diff --git a/lib/api/job_artifacts.rb b/lib/api/job_artifacts.rb index 933bd067e26..e7fed55170e 100644 --- a/lib/api/job_artifacts.rb +++ b/lib/api/job_artifacts.rb @@ -109,6 +109,22 @@ module API status 200 present build, with: Entities::Job end + + desc 'Delete the artifacts files from a job' do + detail 'This feature was introduced in GitLab 11.9' + end + params do + requires :job_id, type: Integer, desc: 'The ID of a job' + end + delete ':id/jobs/:job_id/artifacts' do + authorize_destroy_artifacts! + build = find_build!(params[:job_id]) + authorize!(:destroy_artifacts, build) + + build.erase_erasable_artifacts! + + status :no_content + end end end end diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 44f1e81caf2..123b7a83185 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -45,7 +45,7 @@ module API return merge_requests if args[:view] == 'simple' merge_requests - .preload(:notes, :author, :assignee, :milestone, :latest_merge_request_diff, :labels, :timelogs, metrics: [:latest_closed_by, :merged_by]) + .with_api_entity_associations end # rubocop: enable CodeReuse/ActiveRecord @@ -95,7 +95,7 @@ module API optional :sort, type: String, values: %w[asc desc], default: 'desc', desc: 'Return merge requests sorted in `asc` or `desc` order.' optional :milestone, type: String, desc: 'Return merge requests for a specific milestone' - optional :labels, type: String, desc: 'Comma-separated list of label names' + optional :labels, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names' optional :created_after, type: DateTime, desc: 'Return merge requests created after the specified time' optional :created_before, type: DateTime, desc: 'Return merge requests created before the specified time' optional :updated_after, type: DateTime, desc: 'Return merge requests updated after the specified time' @@ -179,8 +179,8 @@ module API optional :description, type: String, desc: 'The description of the merge request' optional :assignee_id, type: Integer, desc: 'The ID of a user to assign the merge request' optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign the merge request' - optional :labels, type: String, desc: 'Comma-separated list of label names' - optional :remove_source_branch, type: Boolean, desc: 'Delete source branch when merging' + optional :labels, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names' + optional :remove_source_branch, type: Boolean, desc: 'Remove source branch when merging' optional :allow_collaboration, type: Boolean, desc: 'Allow commits from members who can merge to the target branch' optional :allow_maintainer_to_push, type: Boolean, as: :allow_collaboration, desc: '[deprecated] See allow_collaboration' optional :squash, type: Grape::API::Boolean, desc: 'When true, the commits will be squashed into a single commit on merge' diff --git a/lib/api/projects.rb b/lib/api/projects.rb index b23fe6cd4e7..91501ba4d36 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -184,7 +184,8 @@ module API if project.saved? present project, with: Entities::Project, - user_can_admin_project: can?(current_user, :admin_project, project) + user_can_admin_project: can?(current_user, :admin_project, project), + current_user: current_user else if project.errors[:limit_reached].present? error!(project.errors[:limit_reached], 403) @@ -217,7 +218,8 @@ module API if project.saved? present project, with: Entities::Project, - user_can_admin_project: can?(current_user, :admin_project, project) + user_can_admin_project: can?(current_user, :admin_project, project), + current_user: current_user else render_validation_error!(project) end @@ -281,7 +283,8 @@ module API conflict!(forked_project.errors.messages) else present forked_project, with: Entities::Project, - user_can_admin_project: can?(current_user, :admin_project, forked_project) + user_can_admin_project: can?(current_user, :admin_project, forked_project), + current_user: current_user end end @@ -330,7 +333,8 @@ module API if result[:status] == :success present user_project, with: Entities::Project, - user_can_admin_project: can?(current_user, :admin_project, user_project) + user_can_admin_project: can?(current_user, :admin_project, user_project), + current_user: current_user else render_validation_error!(user_project) end @@ -344,7 +348,7 @@ module API ::Projects::UpdateService.new(user_project, current_user, archived: true).execute - present user_project, with: Entities::Project + present user_project, with: Entities::Project, current_user: current_user end desc 'Unarchive a project' do @@ -355,7 +359,7 @@ module API ::Projects::UpdateService.new(@project, current_user, archived: false).execute - present user_project, with: Entities::Project + present user_project, with: Entities::Project, current_user: current_user end desc 'Star a project' do @@ -368,7 +372,7 @@ module API current_user.toggle_star(user_project) user_project.reload - present user_project, with: Entities::Project + present user_project, with: Entities::Project, current_user: current_user end end @@ -380,7 +384,7 @@ module API current_user.toggle_star(user_project) user_project.reload - present user_project, with: Entities::Project + present user_project, with: Entities::Project, current_user: current_user else not_modified! end @@ -420,7 +424,7 @@ module API result = ::Projects::ForkService.new(fork_from_project, current_user).execute(user_project) if result - present user_project.reload, with: Entities::Project + present user_project.reload, with: Entities::Project, current_user: current_user else render_api_error!("Project already forked", 409) if user_project.forked? end @@ -442,27 +446,24 @@ module API end params do requires :group_id, type: Integer, desc: 'The ID of a group' - requires :group_access, type: Integer, values: Gitlab::Access.values, desc: 'The group access level' + requires :group_access, type: Integer, values: Gitlab::Access.values, as: :link_group_access, desc: 'The group access level' optional :expires_at, type: Date, desc: 'Share expiration date' end post ":id/share" do authorize! :admin_project, user_project group = Group.find_by_id(params[:group_id]) - unless group && can?(current_user, :read_group, group) - not_found!('Group') - end - unless user_project.allowed_to_share_with_group? break render_api_error!("The project sharing with group is disabled", 400) end - link = user_project.project_group_links.new(declared_params(include_missing: false)) + result = ::Projects::GroupLinks::CreateService.new(user_project, current_user, declared_params(include_missing: false)) + .execute(group) - if link.save - present link, with: Entities::ProjectGroupLink + if result[:status] == :success + present result[:link], with: Entities::ProjectGroupLink else - render_api_error!(link.errors.full_messages.first, 409) + render_api_error!(result[:message], result[:http_status]) end end @@ -526,7 +527,7 @@ module API result = ::Projects::TransferService.new(user_project, current_user).execute(namespace) if result - present user_project, with: Entities::Project + present user_project, with: Entities::Project, current_user: current_user else render_api_error!("Failed to transfer project #{user_project.errors.messages}", 400) end diff --git a/lib/api/release/links.rb b/lib/api/release/links.rb index e3072684ef7..5d1b40e3bff 100644 --- a/lib/api/release/links.rb +++ b/lib/api/release/links.rb @@ -8,6 +8,8 @@ module API RELEASE_ENDPOINT_REQUIREMETS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS .merge(tag_name: API::NO_SLASH_URL_PART_REGEX) + before { authorize! :read_release, user_project } + params do requires :id, type: String, desc: 'The ID of a project' end diff --git a/lib/api/runners.rb b/lib/api/runners.rb index f72b33605a7..f3fea463e7f 100644 --- a/lib/api/runners.rb +++ b/lib/api/runners.rb @@ -17,6 +17,7 @@ module API desc: 'The type of the runners to show' optional :status, type: String, values: Ci::Runner::AVAILABLE_STATUSES, desc: 'The status of the runners to show' + optional :tag_list, type: Array[String], desc: 'The tags of the runners to show' use :pagination end get do @@ -24,6 +25,7 @@ module API runners = filter_runners(runners, params[:scope], allowed_scopes: Ci::Runner::AVAILABLE_STATUSES) runners = filter_runners(runners, params[:type], allowed_scopes: Ci::Runner::AVAILABLE_TYPES) runners = filter_runners(runners, params[:status], allowed_scopes: Ci::Runner::AVAILABLE_STATUSES) + runners = runners.tagged_with(params[:tag_list]) if params[:tag_list] present paginate(runners), with: Entities::Runner end @@ -38,6 +40,7 @@ module API desc: 'The type of the runners to show' optional :status, type: String, values: Ci::Runner::AVAILABLE_STATUSES, desc: 'The status of the runners to show' + optional :tag_list, type: Array[String], desc: 'The tags of the runners to show' use :pagination end get 'all' do @@ -47,6 +50,7 @@ module API runners = filter_runners(runners, params[:scope]) runners = filter_runners(runners, params[:type], allowed_scopes: Ci::Runner::AVAILABLE_TYPES) runners = filter_runners(runners, params[:status], allowed_scopes: Ci::Runner::AVAILABLE_STATUSES) + runners = runners.tagged_with(params[:tag_list]) if params[:tag_list] present paginate(runners), with: Entities::Runner end @@ -139,6 +143,7 @@ module API desc: 'The type of the runners to show' optional :status, type: String, values: Ci::Runner::AVAILABLE_STATUSES, desc: 'The status of the runners to show' + optional :tag_list, type: Array[String], desc: 'The tags of the runners to show' use :pagination end get ':id/runners' do @@ -146,6 +151,7 @@ module API runners = filter_runners(runners, params[:scope]) runners = filter_runners(runners, params[:type], allowed_scopes: Ci::Runner::AVAILABLE_TYPES) runners = filter_runners(runners, params[:status], allowed_scopes: Ci::Runner::AVAILABLE_STATUSES) + runners = runners.tagged_with(params[:tag_list]) if params[:tag_list] present paginate(runners), with: Entities::Runner end diff --git a/lib/api/snippets.rb b/lib/api/snippets.rb index 326d55afd0e..f8b37b33348 100644 --- a/lib/api/snippets.rb +++ b/lib/api/snippets.rb @@ -16,6 +16,10 @@ module API def public_snippets SnippetsFinder.new(current_user, scope: :are_public).execute end + + def snippets + SnippetsFinder.new(current_user).execute + end end desc 'Get a snippets list for authenticated user' do @@ -48,7 +52,10 @@ module API requires :id, type: Integer, desc: 'The ID of a snippet' end get ':id' do - snippet = snippets_for_current_user.find(params[:id]) + snippet = snippets.find_by_id(params[:id]) + + break not_found!('Snippet') unless snippet + present snippet, with: Entities::PersonalSnippet end @@ -94,9 +101,8 @@ module API desc: 'The visibility of the snippet' at_least_one_of :title, :file_name, :content, :visibility end - # rubocop: disable CodeReuse/ActiveRecord put ':id' do - snippet = snippets_for_current_user.find_by(id: params.delete(:id)) + snippet = snippets_for_current_user.find_by_id(params.delete(:id)) break not_found!('Snippet') unless snippet authorize! :update_personal_snippet, snippet @@ -113,7 +119,6 @@ module API render_validation_error!(snippet) end end - # rubocop: enable CodeReuse/ActiveRecord desc 'Remove snippet' do detail 'This feature was introduced in GitLab 8.15.' @@ -122,16 +127,14 @@ module API params do requires :id, type: Integer, desc: 'The ID of a snippet' end - # rubocop: disable CodeReuse/ActiveRecord delete ':id' do - snippet = snippets_for_current_user.find_by(id: params.delete(:id)) + snippet = snippets_for_current_user.find_by_id(params.delete(:id)) break not_found!('Snippet') unless snippet authorize! :destroy_personal_snippet, snippet destroy_conditionally!(snippet) end - # rubocop: enable CodeReuse/ActiveRecord desc 'Get a raw snippet' do detail 'This feature was introduced in GitLab 8.15.' @@ -139,9 +142,8 @@ module API params do requires :id, type: Integer, desc: 'The ID of a snippet' end - # rubocop: disable CodeReuse/ActiveRecord get ":id/raw" do - snippet = snippets_for_current_user.find_by(id: params.delete(:id)) + snippet = snippets.find_by_id(params.delete(:id)) break not_found!('Snippet') unless snippet env['api.format'] = :txt @@ -149,7 +151,6 @@ module API header['Content-Disposition'] = 'attachment' present snippet.content end - # rubocop: enable CodeReuse/ActiveRecord desc 'Get the user agent details for a snippet' do success Entities::UserAgentDetail @@ -157,17 +158,15 @@ module API params do requires :id, type: Integer, desc: 'The ID of a snippet' end - # rubocop: disable CodeReuse/ActiveRecord get ":id/user_agent_detail" do authenticated_as_admin! - snippet = Snippet.find_by!(id: params[:id]) + snippet = Snippet.find_by_id!(params[:id]) break not_found!('UserAgentDetail') unless snippet.user_agent_detail present snippet.user_agent_detail, with: Entities::UserAgentDetail end - # rubocop: enable CodeReuse/ActiveRecord end end end diff --git a/lib/api/todos.rb b/lib/api/todos.rb index 64ac8ece56c..d2196f05173 100644 --- a/lib/api/todos.rb +++ b/lib/api/todos.rb @@ -6,6 +6,8 @@ module API before { authenticate! } + helpers ::Gitlab::IssuableMetadata + ISSUABLE_TYPES = { 'merge_requests' => ->(iid) { find_merge_request_with_access(iid) }, 'issues' => ->(iid) { find_project_issue(iid) } @@ -42,6 +44,30 @@ module API def find_todos TodosFinder.new(current_user, params).execute end + + def issuable_and_awardable?(type) + obj_type = Object.const_get(type) + + (obj_type < Issuable) && (obj_type < Awardable) + rescue NameError + false + end + + def batch_load_issuable_metadata(todos, options) + # This should be paginated and will cause Rails to SELECT for all the Todos + todos_by_type = todos.group_by(&:target_type) + + todos_by_type.keys.each do |type| + next unless issuable_and_awardable?(type) + + collection = todos_by_type[type] + + next unless collection + + targets = collection.map(&:target) + options[type] = { issuable_metadata: issuable_meta_data(targets, type) } + end + end end desc 'Get a todo list' do @@ -51,7 +77,11 @@ module API use :pagination end get do - present paginate(find_todos), with: Entities::Todo, current_user: current_user + todos = paginate(find_todos.with_api_entity_associations) + options = { with: Entities::Todo, current_user: current_user } + batch_load_issuable_metadata(todos, options) + + present todos, options end desc 'Mark a todo as done' do diff --git a/lib/api/validations/types/labels_list.rb b/lib/api/validations/types/labels_list.rb new file mode 100644 index 00000000000..47cd83c29cf --- /dev/null +++ b/lib/api/validations/types/labels_list.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module API + module Validations + module Types + class LabelsList + def self.coerce + lambda do |value| + case value + when String + value.split(',').map(&:strip) + when Array + value.map { |v| v.to_s.split(',').map(&:strip) }.flatten + when LabelsList + value + else + [] + end + end + end + end + end + end +end diff --git a/lib/api/version.rb b/lib/api/version.rb index 74cd857f447..eca1b529094 100644 --- a/lib/api/version.rb +++ b/lib/api/version.rb @@ -2,13 +2,29 @@ module API class Version < Grape::API + helpers ::API::Helpers::GraphqlHelpers + before { authenticate! } + METADATA_QUERY = <<~EOF + { + metadata { + version + revision + } + } + EOF + desc 'Get the version information of the GitLab instance.' do detail 'This feature was introduced in GitLab 8.13.' end get '/version' do - { version: Gitlab::VERSION, revision: Gitlab.revision } + conditionally_graphql!( + query: METADATA_QUERY, + context: { current_user: current_user }, + transform: ->(result) { result.dig('data', 'metadata') }, + fallback: -> { { version: Gitlab::VERSION, revision: Gitlab.revision } } + ) end end end |