diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-20 18:38:24 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-20 18:38:24 +0000 |
commit | 983a0bba5d2a042c4a3bbb22432ec192c7501d82 (patch) | |
tree | b153cd387c14ba23bd5a07514c7c01fddf6a78a0 /lib/api | |
parent | a2bddee2cdb38673df0e004d5b32d9f77797de64 (diff) | |
download | gitlab-ce-983a0bba5d2a042c4a3bbb22432ec192c7501d82.tar.gz |
Add latest changes from gitlab-org/gitlab@12-10-stable-ee
Diffstat (limited to 'lib/api')
-rw-r--r-- | lib/api/deploy_tokens.rb | 2 | ||||
-rw-r--r-- | lib/api/discussions.rb | 5 | ||||
-rw-r--r-- | lib/api/entities/container_expiration_policy.rb | 1 | ||||
-rw-r--r-- | lib/api/entities/merge_request.rb | 10 | ||||
-rw-r--r-- | lib/api/entities/merge_request_basic.rb | 2 | ||||
-rw-r--r-- | lib/api/entities/project_import_failed_relation.rb | 11 | ||||
-rw-r--r-- | lib/api/entities/project_import_status.rb | 4 | ||||
-rw-r--r-- | lib/api/entities/user.rb | 4 | ||||
-rw-r--r-- | lib/api/helpers/internal_helpers.rb | 19 | ||||
-rw-r--r-- | lib/api/helpers/projects_helpers.rb | 1 | ||||
-rw-r--r-- | lib/api/merge_requests.rb | 1 | ||||
-rw-r--r-- | lib/api/project_statistics.rb | 1 | ||||
-rw-r--r-- | lib/api/services.rb | 4 | ||||
-rw-r--r-- | lib/api/terraform/state.rb | 106 | ||||
-rw-r--r-- | lib/api/validations/validators/limit.rb | 19 |
15 files changed, 163 insertions, 27 deletions
diff --git a/lib/api/deploy_tokens.rb b/lib/api/deploy_tokens.rb index 5de36c14d7b..f3a08ae970a 100644 --- a/lib/api/deploy_tokens.rb +++ b/lib/api/deploy_tokens.rb @@ -8,7 +8,7 @@ module API def scope_params scopes = params.delete(:scopes) - result_hash = {} + result_hash = Hashie::Mash.new result_hash[:read_registry] = scopes.include?('read_registry') result_hash[:write_registry] = scopes.include?('write_registry') result_hash[:read_repository] = scopes.include?('read_repository') diff --git a/lib/api/discussions.rb b/lib/api/discussions.rb index 8ff275a3a1b..0dd1850e526 100644 --- a/lib/api/discussions.rb +++ b/lib/api/discussions.rb @@ -74,6 +74,11 @@ module API optional :height, type: Integer, desc: 'Height of the image' optional :x, type: Integer, desc: 'X coordinate in the image' optional :y, type: Integer, desc: 'Y coordinate in the image' + + optional :line_range, type: Hash, desc: 'Multi-line start and end' do + requires :start_line_code, type: String, desc: 'Start line code for multi-line note' + requires :end_line_code, type: String, desc: 'End line code for multi-line note' + end end end post ":id/#{noteables_path}/:noteable_id/discussions" do diff --git a/lib/api/entities/container_expiration_policy.rb b/lib/api/entities/container_expiration_policy.rb index 853bbb9b76b..b2240704b99 100644 --- a/lib/api/entities/container_expiration_policy.rb +++ b/lib/api/entities/container_expiration_policy.rb @@ -8,6 +8,7 @@ module API expose :keep_n expose :older_than expose :name_regex + expose :name_regex_keep expose :next_run_at end end diff --git a/lib/api/entities/merge_request.rb b/lib/api/entities/merge_request.rb index 9ff8e20ced1..7fc76a4071e 100644 --- a/lib/api/entities/merge_request.rb +++ b/lib/api/entities/merge_request.rb @@ -39,6 +39,16 @@ module API expose :diverged_commits_count, as: :diverged_commits_count, if: -> (_, options) { options[:include_diverged_commits_count] } + # We put this into an option because list of TODOs API will attach their + # targets with Entities::MergeRequest instead of + # Entities::MergeRequestBasic, but this attribute cannot be eagerly + # loaded in batch for now. The list of merge requests API will + # use Entities::MergeRequestBasic which does not support this, and + # we always enable this for the single merge request API. This way + # we avoid N+1 queries in the TODOs API and can still enable it for + # the single merge request API. + expose :first_contribution?, as: :first_contribution, if: -> (_, options) { options[:include_first_contribution] } + def build_available?(options) options[:project]&.feature_available?(:builds, options[:current_user]) end diff --git a/lib/api/entities/merge_request_basic.rb b/lib/api/entities/merge_request_basic.rb index 8cec2c1a97e..4610220e4f6 100644 --- a/lib/api/entities/merge_request_basic.rb +++ b/lib/api/entities/merge_request_basic.rb @@ -52,7 +52,7 @@ module API # information. expose :merge_status do |merge_request| merge_request.check_mergeability(async: true) - merge_request.merge_status + merge_request.public_merge_status end expose :diff_head_sha, as: :sha expose :merge_commit_sha diff --git a/lib/api/entities/project_import_failed_relation.rb b/lib/api/entities/project_import_failed_relation.rb new file mode 100644 index 00000000000..16b26ad0efa --- /dev/null +++ b/lib/api/entities/project_import_failed_relation.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module API + module Entities + class ProjectImportFailedRelation < Grape::Entity + expose :id, :created_at, :exception_class, :exception_message, :source + + expose :relation_key, as: :relation_name + end + end +end diff --git a/lib/api/entities/project_import_status.rb b/lib/api/entities/project_import_status.rb index de7b4b998be..5ef5600259f 100644 --- a/lib/api/entities/project_import_status.rb +++ b/lib/api/entities/project_import_status.rb @@ -8,6 +8,10 @@ module API project.import_state&.correlation_id end + expose :failed_relations, using: Entities::ProjectImportFailedRelation do |project, _options| + project.import_state.relation_hard_failures(limit: 100) + end + # TODO: Use `expose_nil` once we upgrade the grape-entity gem expose :import_error, if: lambda { |project, _ops| project.import_state&.last_error } do |project| project.import_state.last_error diff --git a/lib/api/entities/user.rb b/lib/api/entities/user.rb index 4a1f570c3f0..adf954ab02d 100644 --- a/lib/api/entities/user.rb +++ b/lib/api/entities/user.rb @@ -3,8 +3,12 @@ module API module Entities class User < UserBasic + include UsersHelper expose :created_at, if: ->(user, opts) { Ability.allowed?(opts[:current_user], :read_user_profile, user) } expose :bio, :location, :public_email, :skype, :linkedin, :twitter, :website_url, :organization, :job_title + expose :work_information do |user| + work_information(user) + end end end end diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb index f7aabc8ce4f..31272c537a3 100644 --- a/lib/api/helpers/internal_helpers.rb +++ b/lib/api/helpers/internal_helpers.rb @@ -3,7 +3,7 @@ module API module Helpers module InternalHelpers - attr_reader :redirected_path, :container + attr_reader :redirected_path delegate :wiki?, to: :repo_type @@ -11,15 +11,22 @@ module API @actor ||= Support::GitAccessActor.from_params(params) end + # rubocop:disable Gitlab/ModuleWithInstanceVariables def repo_type - set_project unless defined?(@repo_type) # rubocop:disable Gitlab/ModuleWithInstanceVariables - @repo_type # rubocop:disable Gitlab/ModuleWithInstanceVariables + parse_repo_path unless defined?(@repo_type) + @repo_type end def project - set_project unless defined?(@project) # rubocop:disable Gitlab/ModuleWithInstanceVariables - @project # rubocop:disable Gitlab/ModuleWithInstanceVariables + parse_repo_path unless defined?(@project) + @project + end + + def container + parse_repo_path unless defined?(@container) + @container end + # rubocop:enable Gitlab/ModuleWithInstanceVariables def access_checker_for(actor, protocol) access_checker_klass.new(actor.key_or_user, container, protocol, @@ -79,7 +86,7 @@ module API end # rubocop:disable Gitlab/ModuleWithInstanceVariables - def set_project + def parse_repo_path @container, @project, @repo_type, @redirected_path = if params[:gl_repository] Gitlab::GlRepository.parse(params[:gl_repository]) diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb index 8ad682fc961..14c83114f32 100644 --- a/lib/api/helpers/projects_helpers.rb +++ b/lib/api/helpers/projects_helpers.rb @@ -85,6 +85,7 @@ module API optional :keep_n, type: String, desc: 'Container expiration policy number of images to keep' optional :older_than, type: String, desc: 'Container expiration policy remove images older than value' optional :name_regex, type: String, desc: 'Container expiration policy regex for image removal' + optional :name_regex_keep, type: String, desc: 'Container expiration policy regex for image retention' optional :enabled, type: Boolean, desc: 'Flag indication if container expiration policy is enabled' end diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 4d9f035e2cd..d45786cdd3d 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -267,6 +267,7 @@ module API current_user: current_user, project: user_project, render_html: params[:render_html], + include_first_contribution: true, include_diverged_commits_count: params[:include_diverged_commits_count], include_rebase_in_progress: params[:include_rebase_in_progress] end diff --git a/lib/api/project_statistics.rb b/lib/api/project_statistics.rb index 2f73785f72d..14ee0f75513 100644 --- a/lib/api/project_statistics.rb +++ b/lib/api/project_statistics.rb @@ -4,7 +4,6 @@ module API class ProjectStatistics < Grape::API before do authenticate! - not_found! unless user_project.daily_statistics_enabled? authorize! :daily_statistics, user_project end diff --git a/lib/api/services.rb b/lib/api/services.rb index a3b5d2cc4b7..5fd5c6bd9b0 100644 --- a/lib/api/services.rb +++ b/lib/api/services.rb @@ -130,13 +130,11 @@ module API TRIGGER_SERVICES.each do |service_slug, settings| helpers do - # rubocop: disable CodeReuse/ActiveRecord def slash_command_service(project, service_slug, params) - project.services.active.where(template: false).find do |service| + project.services.active.find do |service| service.try(:token) == params[:token] && service.to_param == service_slug.underscore end end - # rubocop: enable CodeReuse/ActiveRecord end params do diff --git a/lib/api/terraform/state.rb b/lib/api/terraform/state.rb index 7e55dfedfeb..052c75188ab 100644 --- a/lib/api/terraform/state.rb +++ b/lib/api/terraform/state.rb @@ -1,41 +1,117 @@ # frozen_string_literal: true +require_dependency 'api/validations/validators/limit' + module API module Terraform class State < Grape::API - before { authenticate! } - before { authorize! :admin_terraform_state, user_project } + include ::Gitlab::Utils::StrongMemoize + + default_format :json + + before do + authenticate! + authorize! :admin_terraform_state, user_project + end params do requires :id, type: String, desc: 'The ID of a project' end + resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do - params do - requires :name, type: String, desc: 'The name of a terraform state' - end namespace ':id/terraform/state/:name' do + params do + requires :name, type: String, desc: 'The name of a Terraform state' + optional :ID, type: String, limit: 255, desc: 'Terraform state lock ID' + end + + helpers do + def remote_state_handler + ::Terraform::RemoteStateHandler.new(user_project, current_user, name: params[:name], lock_id: params[:ID]) + end + end + desc 'Get a terraform state by its name' route_setting :authentication, basic_auth_personal_access_token: true get do - status 501 - content_type 'text/plain' - body 'not implemented' + remote_state_handler.find_with_lock do |state| + no_content! unless state.file.exists? + + env['api.format'] = :binary # this bypasses json serialization + body state.file.read + status :ok + end end desc 'Add a new terraform state or update an existing one' route_setting :authentication, basic_auth_personal_access_token: true post do - status 501 - content_type 'text/plain' - body 'not implemented' + data = request.body.string + no_content! if data.empty? + + remote_state_handler.handle_with_lock do |state| + state.file = CarrierWaveStringFile.new(data) + state.save! + status :ok + end end - desc 'Delete a terraform state of certain name' + desc 'Delete a terraform state of a certain name' route_setting :authentication, basic_auth_personal_access_token: true delete do - status 501 - content_type 'text/plain' - body 'not implemented' + remote_state_handler.handle_with_lock do |state| + state.destroy! + status :ok + end + end + + desc 'Lock a terraform state of a certain name' + route_setting :authentication, basic_auth_personal_access_token: true + params do + requires :ID, type: String, limit: 255, desc: 'Terraform state lock ID' + requires :Operation, type: String, desc: 'Terraform operation' + requires :Info, type: String, desc: 'Terraform info' + requires :Who, type: String, desc: 'Terraform state lock owner' + requires :Version, type: String, desc: 'Terraform version' + requires :Created, type: String, desc: 'Terraform state lock timestamp' + requires :Path, type: String, desc: 'Terraform path' + end + post '/lock' do + status_code = :ok + lock_info = { + 'Operation' => params[:Operation], + 'Info' => params[:Info], + 'Version' => params[:Version], + 'Path' => params[:Path] + } + + begin + remote_state_handler.lock! + rescue ::Terraform::RemoteStateHandler::StateLockedError + status_code = :conflict + end + + remote_state_handler.find_with_lock do |state| + lock_info['ID'] = state.lock_xid + lock_info['Who'] = state.locked_by_user.username + lock_info['Created'] = state.locked_at + + env['api.format'] = :binary # this bypasses json serialization + body lock_info.to_json + status status_code + end + end + + desc 'Unlock a terraform state of a certain name' + route_setting :authentication, basic_auth_personal_access_token: true + params do + optional :ID, type: String, limit: 255, desc: 'Terraform state lock ID' + end + delete '/lock' do + remote_state_handler.unlock! + status :ok + rescue ::Terraform::RemoteStateHandler::StateLockedError + status :conflict end end end diff --git a/lib/api/validations/validators/limit.rb b/lib/api/validations/validators/limit.rb new file mode 100644 index 00000000000..3bb4cee1d75 --- /dev/null +++ b/lib/api/validations/validators/limit.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module API + module Validations + module Validators + class Limit < Grape::Validations::Base + def validate_param!(attr_name, params) + value = params[attr_name] + + return if value.size <= @option + + raise Grape::Exceptions::Validation, + params: [@scope.full_name(attr_name)], + message: "#{@scope.full_name(attr_name)} must be less than #{@option} characters" + end + end + end + end +end |