diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-03 18:06:49 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-03 18:06:49 +0000 |
commit | ab7cf450ba19cf80b9534f25dc707b33845e3014 (patch) | |
tree | bbfa6aba83c48aea68d79c4179ce576b6eec326d /app | |
parent | 4204cf308596e0e26f578a6e2da88f49c0f4aad9 (diff) | |
download | gitlab-ce-ab7cf450ba19cf80b9534f25dc707b33845e3014.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
48 files changed, 389 insertions, 198 deletions
diff --git a/app/assets/javascripts/pages/instance_statistics/conversational_development_index/index.js b/app/assets/javascripts/pages/instance_statistics/dev_ops_score/index.js index c1056537f90..c1056537f90 100644 --- a/app/assets/javascripts/pages/instance_statistics/conversational_development_index/index.js +++ b/app/assets/javascripts/pages/instance_statistics/dev_ops_score/index.js diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 25c1d80b117..4d55d7f00f0 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -20,11 +20,11 @@ class ApplicationController < ActionController::Base before_action :authenticate_user!, except: [:route_not_found] before_action :enforce_terms!, if: :should_enforce_terms? before_action :validate_user_service_ticket! - before_action :check_password_expiration + before_action :check_password_expiration, if: :html_request? before_action :ldap_security_check before_action :sentry_context before_action :default_headers - before_action :add_gon_variables, unless: [:peek_request?, :json_request?] + before_action :add_gon_variables, if: :html_request? before_action :configure_permitted_parameters, if: :devise_controller? before_action :require_email, unless: :devise_controller? before_action :active_user_check, unless: :devise_controller? @@ -455,8 +455,8 @@ class ApplicationController < ActionController::Base response.headers['Page-Title'] = URI.escape(page_title('GitLab')) end - def peek_request? - request.path.start_with?('/-/peek') + def html_request? + request.format.html? end def json_request? @@ -466,7 +466,7 @@ class ApplicationController < ActionController::Base def should_enforce_terms? return false unless Gitlab::CurrentSettings.current_application_settings.enforce_terms - !(peek_request? || devise_controller?) + html_request? && !devise_controller? end def set_usage_stats_consent_flag diff --git a/app/controllers/concerns/confirm_email_warning.rb b/app/controllers/concerns/confirm_email_warning.rb index 86df0010665..32e1a46e580 100644 --- a/app/controllers/concerns/confirm_email_warning.rb +++ b/app/controllers/concerns/confirm_email_warning.rb @@ -4,15 +4,18 @@ module ConfirmEmailWarning extend ActiveSupport::Concern included do - before_action :set_confirm_warning, if: -> { Feature.enabled?(:soft_email_confirmation) } + before_action :set_confirm_warning, if: :show_confirm_warning? end protected + def show_confirm_warning? + html_request? && request.get? && Feature.enabled?(:soft_email_confirmation) + end + def set_confirm_warning return unless current_user return if current_user.confirmed? - return if peek_request? || json_request? || !request.get? email = current_user.unconfirmed_email || current_user.email diff --git a/app/controllers/concerns/sourcegraph_gon.rb b/app/controllers/concerns/sourcegraph_gon.rb index ab4abd734fb..01925cf9d4d 100644 --- a/app/controllers/concerns/sourcegraph_gon.rb +++ b/app/controllers/concerns/sourcegraph_gon.rb @@ -4,7 +4,7 @@ module SourcegraphGon extend ActiveSupport::Concern included do - before_action :push_sourcegraph_gon, unless: :json_request? + before_action :push_sourcegraph_gon, if: :html_request? end private diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb index b87779c22d3..9b3b2c4a482 100644 --- a/app/controllers/concerns/uploads_actions.rb +++ b/app/controllers/concerns/uploads_actions.rb @@ -1,11 +1,16 @@ # frozen_string_literal: true module UploadsActions + extend ActiveSupport::Concern include Gitlab::Utils::StrongMemoize include SendFileUpload UPLOAD_MOUNTS = %w(avatar attachment file logo header_logo favicon).freeze + included do + prepend_before_action :set_request_format_from_path_extension + end + def create uploader = UploadService.new(model, params[:file], uploader_class).execute @@ -64,6 +69,20 @@ module UploadsActions private + # Based on ActionDispatch::Http::MimeNegotiation. We have an + # initializer that monkey-patches this method out (so that repository + # paths don't guess a format based on extension), but we do want this + # behavior when serving uploads. + def set_request_format_from_path_extension + path = request.headers['action_dispatch.original_path'] || request.headers['PATH_INFO'] + + if match = path&.match(/\.(\w+)\z/) + format = Mime[match.captures.first] + + request.format = format.symbol if format + end + end + def uploader_class raise NotImplementedError end diff --git a/app/controllers/instance_statistics/conversational_development_index_controller.rb b/app/controllers/instance_statistics/dev_ops_score_controller.rb index f34347b4d22..238f7fa7707 100644 --- a/app/controllers/instance_statistics/conversational_development_index_controller.rb +++ b/app/controllers/instance_statistics/dev_ops_score_controller.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class InstanceStatistics::ConversationalDevelopmentIndexController < InstanceStatistics::ApplicationController +class InstanceStatistics::DevOpsScoreController < InstanceStatistics::ApplicationController # rubocop: disable CodeReuse/ActiveRecord def index @metric = DevOpsScore::Metric.order(:created_at).last&.present diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index a908da08f57..09754409104 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -46,7 +46,7 @@ class Projects::BranchesController < Projects::ApplicationController def diverging_commit_counts respond_to do |format| format.json do - service = Branches::DivergingCommitCountsService.new(repository) + service = ::Branches::DivergingCommitCountsService.new(repository) branches = BranchesFinder.new(repository, params.permit(names: [])).execute Gitlab::GitalyClient.allow_n_plus_1_calls do @@ -63,7 +63,7 @@ class Projects::BranchesController < Projects::ApplicationController redirect_to_autodeploy = project.empty_repo? && project.deployment_platform.present? - result = CreateBranchService.new(project, current_user) + result = ::Branches::CreateService.new(project, current_user) .execute(branch_name, ref) success = (result[:status] == :success) @@ -102,7 +102,7 @@ class Projects::BranchesController < Projects::ApplicationController def destroy @branch_name = Addressable::URI.unescape(params[:id]) - result = DeleteBranchService.new(project, current_user).execute(@branch_name) + result = ::Branches::DeleteService.new(project, current_user).execute(@branch_name) respond_to do |format| format.html do @@ -118,7 +118,7 @@ class Projects::BranchesController < Projects::ApplicationController end def destroy_all_merged - DeleteMergedBranchesService.new(@project, current_user).async_execute + ::Branches::DeleteMergedService.new(@project, current_user).async_execute redirect_to project_branches_path(@project), notice: _('Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes.') diff --git a/app/finders/clusters/knative_version_role_binding_finder.rb b/app/finders/clusters/knative_version_role_binding_finder.rb new file mode 100644 index 00000000000..06ec5ea557f --- /dev/null +++ b/app/finders/clusters/knative_version_role_binding_finder.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Clusters + class KnativeVersionRoleBindingFinder + attr_reader :cluster + + def initialize(cluster) + @cluster = cluster + end + + def execute + cluster&.kubeclient&.get_cluster_role_bindings&.find do |resource| + resource.metadata.name == Clusters::Kubernetes::GITLAB_KNATIVE_VERSION_ROLE_BINDING_NAME + end + end + end +end diff --git a/app/graphql/mutations/issues/set_confidential.rb b/app/graphql/mutations/issues/set_confidential.rb new file mode 100644 index 00000000000..0fff5518665 --- /dev/null +++ b/app/graphql/mutations/issues/set_confidential.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Mutations + module Issues + class SetConfidential < Base + graphql_name 'IssueSetConfidential' + + argument :confidential, + GraphQL::BOOLEAN_TYPE, + required: true, + description: 'Whether or not to set the issue as a confidential.' + + def resolve(project_path:, iid:, confidential:) + issue = authorized_find!(project_path: project_path, iid: iid) + project = issue.project + + ::Issues::UpdateService.new(project, current_user, confidential: confidential) + .execute(issue) + + { + issue: issue, + errors: issue.errors.full_messages + } + end + end + end +end diff --git a/app/graphql/mutations/todos/mark_done.rb b/app/graphql/mutations/todos/mark_done.rb index 5483708b5c6..d738e387c43 100644 --- a/app/graphql/mutations/todos/mark_done.rb +++ b/app/graphql/mutations/todos/mark_done.rb @@ -16,22 +16,21 @@ module Mutations null: false, description: 'The requested todo' - # rubocop: disable CodeReuse/ActiveRecord def resolve(id:) todo = authorized_find!(id: id) - mark_done(Todo.where(id: todo.id)) unless todo.done? + + mark_done(todo) { todo: todo.reset, errors: errors_on_object(todo) } end - # rubocop: enable CodeReuse/ActiveRecord private def mark_done(todo) - TodoService.new.mark_todos_as_done(todo, current_user) + TodoService.new.mark_todo_as_done(todo, current_user) end end end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index ecdbba477d7..e8f4ec06177 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -9,6 +9,7 @@ module Types mount_mutation Mutations::AwardEmojis::Add mount_mutation Mutations::AwardEmojis::Remove mount_mutation Mutations::AwardEmojis::Toggle + mount_mutation Mutations::Issues::SetConfidential mount_mutation Mutations::Issues::SetDueDate mount_mutation Mutations::MergeRequests::SetLabels mount_mutation Mutations::MergeRequests::SetLocked diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index caa4478c848..1293b0d0f59 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -425,6 +425,18 @@ module Ci end end + def expanded_kubernetes_namespace + return unless has_environment? + + namespace = options.dig(:environment, :kubernetes, :namespace) + + if namespace.present? + strong_memoize(:expanded_kubernetes_namespace) do + ExpandVariables.expand(namespace, -> { simple_variables }) + end + end + end + def has_environment? environment.present? end diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb index 314ef78757d..ae720065387 100644 --- a/app/models/clusters/platforms/kubernetes.rb +++ b/app/models/clusters/platforms/kubernetes.rb @@ -63,7 +63,7 @@ module Clusters default_value_for :authorization_type, :rbac - def predefined_variables(project:, environment_name:) + def predefined_variables(project:, environment_name:, kubernetes_namespace: nil) Gitlab::Ci::Variables::Collection.new.tap do |variables| variables.append(key: 'KUBE_URL', value: api_url) @@ -74,15 +74,15 @@ module Clusters end if !cluster.managed? || cluster.management_project == project - namespace = Gitlab::Kubernetes::DefaultNamespace.new(cluster, project: project).from_environment_name(environment_name) + namespace = kubernetes_namespace || default_namespace(project, environment_name: environment_name) variables .append(key: 'KUBE_TOKEN', value: token, public: false, masked: true) .append(key: 'KUBE_NAMESPACE', value: namespace) .append(key: 'KUBECONFIG', value: kubeconfig(namespace), public: false, file: true) - elsif kubernetes_namespace = find_persisted_namespace(project, environment_name: environment_name) - variables.concat(kubernetes_namespace.predefined_variables) + elsif persisted_namespace = find_persisted_namespace(project, environment_name: environment_name) + variables.concat(persisted_namespace.predefined_variables) end variables.concat(cluster.predefined_variables) @@ -107,6 +107,13 @@ module Clusters private + def default_namespace(project, environment_name:) + Gitlab::Kubernetes::DefaultNamespace.new( + cluster, + project: project + ).from_environment_name(environment_name) + end + def find_persisted_namespace(project, environment_name:) Clusters::KubernetesNamespaceFinder.new( cluster, diff --git a/app/models/concerns/ci/contextable.rb b/app/models/concerns/ci/contextable.rb index b65e9096d4e..5ff537a7837 100644 --- a/app/models/concerns/ci/contextable.rb +++ b/app/models/concerns/ci/contextable.rb @@ -15,7 +15,7 @@ module Ci variables.concat(project.predefined_variables) variables.concat(pipeline.predefined_variables) variables.concat(runner.predefined_variables) if runnable? && runner - variables.concat(project.deployment_variables(environment: environment)) if environment + variables.concat(deployment_variables(environment: environment)) variables.concat(yaml_variables) variables.concat(user_variables) variables.concat(secret_group_variables) @@ -72,6 +72,15 @@ module Ci end end + def deployment_variables(environment:) + return [] unless environment + + project.deployment_variables( + environment: environment, + kubernetes_namespace: expanded_kubernetes_namespace + ) + end + def secret_group_variables return [] unless project.group diff --git a/app/models/dashboard_group_milestone.rb b/app/models/dashboard_group_milestone.rb index cf6094682f3..48c09f4cd6b 100644 --- a/app/models/dashboard_group_milestone.rb +++ b/app/models/dashboard_group_milestone.rb @@ -22,4 +22,8 @@ class DashboardGroupMilestone < GlobalMilestone def dashboard_milestone? true end + + def merge_requests_enabled? + true + end end diff --git a/app/models/dashboard_milestone.rb b/app/models/dashboard_milestone.rb index 9b377b70e5b..fd59b94b737 100644 --- a/app/models/dashboard_milestone.rb +++ b/app/models/dashboard_milestone.rb @@ -12,4 +12,8 @@ class DashboardMilestone < GlobalMilestone def project_milestone? true end + + def merge_requests_enabled? + project.merge_requests_enabled? + end end diff --git a/app/models/group_milestone.rb b/app/models/group_milestone.rb index bfda603c3cb..87338512d99 100644 --- a/app/models/group_milestone.rb +++ b/app/models/group_milestone.rb @@ -41,4 +41,8 @@ class GroupMilestone < GlobalMilestone def legacy_group_milestone? true end + + def merge_requests_enabled? + true + end end diff --git a/app/models/milestone.rb b/app/models/milestone.rb index d0be54eed02..d29eb62af7a 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -274,6 +274,16 @@ class Milestone < ApplicationRecord project_id.present? end + def merge_requests_enabled? + if group_milestone? + # Assume that groups have at least one project with merge requests enabled. + # Otherwise, we would need to load all of the projects from the database. + true + elsif project_milestone? + project&.merge_requests_enabled? + end + end + private # Milestone titles must be unique across project milestones and group milestones diff --git a/app/models/project.rb b/app/models/project.rb index 14207c48f66..03a99577d5c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1986,12 +1986,16 @@ class Project < ApplicationRecord end end - def deployment_variables(environment:) + def deployment_variables(environment:, kubernetes_namespace: nil) platform = deployment_platform(environment: environment) return [] unless platform.present? - platform.predefined_variables(project: self, environment_name: environment) + platform.predefined_variables( + project: self, + environment_name: environment, + kubernetes_namespace: kubernetes_namespace + ) end def auto_devops_variables diff --git a/app/services/branches/create_service.rb b/app/services/branches/create_service.rb new file mode 100644 index 00000000000..c8afd97e6bf --- /dev/null +++ b/app/services/branches/create_service.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Branches + class CreateService < BaseService + def execute(branch_name, ref, create_master_if_empty: true) + create_master_branch if create_master_if_empty && project.empty_repo? + + result = ::Branches::ValidateNewService.new(project).execute(branch_name) + + return result if result[:status] == :error + + new_branch = repository.add_branch(current_user, branch_name, ref) + + if new_branch + success(new_branch) + else + error("Invalid reference name: #{branch_name}") + end + rescue Gitlab::Git::PreReceiveError => ex + error(ex.message) + end + + def success(branch) + super().merge(branch: branch) + end + + private + + def create_master_branch + project.repository.create_file( + current_user, + '/README.md', + '', + message: 'Add README.md', + branch_name: 'master' + ) + end + end +end diff --git a/app/services/branches/delete_merged_service.rb b/app/services/branches/delete_merged_service.rb new file mode 100644 index 00000000000..9fd5964bf94 --- /dev/null +++ b/app/services/branches/delete_merged_service.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Branches + class DeleteMergedService < BaseService + def async_execute + DeleteMergedBranchesWorker.perform_async(project.id, current_user.id) + end + + def execute + raise Gitlab::Access::AccessDeniedError unless can?(current_user, :push_code, project) + + branches = project.repository.merged_branch_names + # Prevent deletion of branches relevant to open merge requests + branches -= merge_request_branch_names + # Prevent deletion of protected branches + branches = branches.reject { |branch| ProtectedBranch.protected?(project, branch) } + + branches.each do |branch| + ::Branches::DeleteService.new(project, current_user).execute(branch) + end + end + + private + + # rubocop: disable CodeReuse/ActiveRecord + def merge_request_branch_names + # reorder(nil) is necessary for SELECT DISTINCT because default scope adds an ORDER BY + source_names = project.origin_merge_requests.opened.reorder(nil).distinct.pluck(:source_branch) + target_names = project.merge_requests.opened.reorder(nil).distinct.pluck(:target_branch) + (source_names + target_names).uniq + end + # rubocop: enable CodeReuse/ActiveRecord + end +end diff --git a/app/services/branches/delete_service.rb b/app/services/branches/delete_service.rb new file mode 100644 index 00000000000..ca2b4556b58 --- /dev/null +++ b/app/services/branches/delete_service.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Branches + class DeleteService < BaseService + def execute(branch_name) + repository = project.repository + branch = repository.find_branch(branch_name) + + unless current_user.can?(:push_code, project) + return ServiceResponse.error( + message: 'You dont have push access to repo', + http_status: 405) + end + + unless branch + return ServiceResponse.error( + message: 'No such branch', + http_status: 404) + end + + if repository.rm_branch(current_user, branch_name) + ServiceResponse.success(message: 'Branch was deleted') + else + ServiceResponse.error( + message: 'Failed to remove branch', + http_status: 400) + end + rescue Gitlab::Git::PreReceiveError => ex + ServiceResponse.error(message: ex.message, http_status: 400) + end + end +end diff --git a/app/services/branches/validate_new_service.rb b/app/services/branches/validate_new_service.rb new file mode 100644 index 00000000000..e45183d160f --- /dev/null +++ b/app/services/branches/validate_new_service.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Branches + class ValidateNewService < BaseService + def initialize(project) + @project = project + end + + def execute(branch_name, force: false) + return error('Branch name is invalid') unless valid_name?(branch_name) + + if branch_exist?(branch_name) && !force + return error('Branch already exists') + end + + success + rescue Gitlab::Git::PreReceiveError => ex + error(ex.message) + end + + private + + def valid_name?(branch_name) + Gitlab::GitRefValidator.validate(branch_name) + end + + def branch_exist?(branch_name) + project.repository.branch_exists?(branch_name) + end + end +end diff --git a/app/services/clusters/kubernetes/create_or_update_service_account_service.rb b/app/services/clusters/kubernetes/create_or_update_service_account_service.rb index d798dcdcfd3..0fea398d234 100644 --- a/app/services/clusters/kubernetes/create_or_update_service_account_service.rb +++ b/app/services/clusters/kubernetes/create_or_update_service_account_service.rb @@ -49,8 +49,14 @@ module Clusters create_or_update_knative_serving_role create_or_update_knative_serving_role_binding + create_or_update_crossplane_database_role create_or_update_crossplane_database_role_binding + + return unless knative_serving_namespace + + create_or_update_knative_version_role + create_or_update_knative_version_role_binding end private @@ -64,6 +70,12 @@ module Clusters ).ensure_exists! end + def knative_serving_namespace + kubeclient.core_client.get_namespaces.find do |namespace| + namespace.metadata.name == Clusters::Kubernetes::KNATIVE_SERVING_NAMESPACE + end + end + def create_role_or_cluster_role_binding if namespace_creator kubeclient.create_or_update_role_binding(role_binding_resource) @@ -88,6 +100,14 @@ module Clusters kubeclient.update_role_binding(crossplane_database_role_binding_resource) end + def create_or_update_knative_version_role + kubeclient.update_cluster_role(knative_version_role_resource) + end + + def create_or_update_knative_version_role_binding + kubeclient.update_cluster_role_binding(knative_version_role_binding_resource) + end + def service_account_resource Gitlab::Kubernetes::ServiceAccount.new( service_account_name, @@ -166,6 +186,27 @@ module Clusters service_account_name: service_account_name ).generate end + + def knative_version_role_resource + Gitlab::Kubernetes::ClusterRole.new( + name: Clusters::Kubernetes::GITLAB_KNATIVE_VERSION_ROLE_NAME, + rules: [{ + apiGroups: %w(apps), + resources: %w(deployments), + verbs: %w(list get) + }] + ).generate + end + + def knative_version_role_binding_resource + subjects = [{ kind: 'ServiceAccount', name: service_account_name, namespace: service_account_namespace }] + + Gitlab::Kubernetes::ClusterRoleBinding.new( + Clusters::Kubernetes::GITLAB_KNATIVE_VERSION_ROLE_BINDING_NAME, + Clusters::Kubernetes::GITLAB_KNATIVE_VERSION_ROLE_NAME, + subjects + ).generate + end end end end diff --git a/app/services/clusters/kubernetes/kubernetes.rb b/app/services/clusters/kubernetes/kubernetes.rb index d29519999b2..59cb1c4b3a9 100644 --- a/app/services/clusters/kubernetes/kubernetes.rb +++ b/app/services/clusters/kubernetes/kubernetes.rb @@ -12,5 +12,8 @@ module Clusters GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME = 'gitlab-knative-serving-rolebinding' GITLAB_CROSSPLANE_DATABASE_ROLE_NAME = 'gitlab-crossplane-database-role' GITLAB_CROSSPLANE_DATABASE_ROLE_BINDING_NAME = 'gitlab-crossplane-database-rolebinding' + GITLAB_KNATIVE_VERSION_ROLE_NAME = 'gitlab-knative-version-role' + GITLAB_KNATIVE_VERSION_ROLE_BINDING_NAME = 'gitlab-knative-version-rolebinding' + KNATIVE_SERVING_NAMESPACE = 'knative-serving' end end diff --git a/app/services/commits/commit_patch_service.rb b/app/services/commits/commit_patch_service.rb index 49113c3c691..4fa6c30e901 100644 --- a/app/services/commits/commit_patch_service.rb +++ b/app/services/commits/commit_patch_service.rb @@ -32,7 +32,7 @@ module Commits end def prepare_branch! - branch_result = CreateBranchService.new(project, current_user) + branch_result = ::Branches::CreateService.new(project, current_user) .execute(@branch_name, @start_branch) if branch_result[:status] != :success diff --git a/app/services/commits/create_service.rb b/app/services/commits/create_service.rb index b42494563b2..bd238605ac1 100644 --- a/app/services/commits/create_service.rb +++ b/app/services/commits/create_service.rb @@ -101,7 +101,7 @@ module Commits end def validate_new_branch_name! - result = ValidateNewBranchService.new(project, current_user).execute(@branch_name, force: force?) + result = ::Branches::ValidateNewService.new(project).execute(@branch_name, force: force?) if result[:status] == :error raise_error("Something went wrong when we tried to create '#{@branch_name}' for you: #{result[:message]}") diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb deleted file mode 100644 index d58cb0f9e2b..00000000000 --- a/app/services/create_branch_service.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -class CreateBranchService < BaseService - def execute(branch_name, ref, create_master_if_empty: true) - create_master_branch if create_master_if_empty && project.empty_repo? - - result = ValidateNewBranchService.new(project, current_user) - .execute(branch_name) - - return result if result[:status] == :error - - new_branch = repository.add_branch(current_user, branch_name, ref) - - if new_branch - success(new_branch) - else - error("Invalid reference name: #{branch_name}") - end - rescue Gitlab::Git::PreReceiveError => ex - error(ex.message) - end - - def success(branch) - super().merge(branch: branch) - end - - private - - def create_master_branch - project.repository.create_file( - current_user, - '/README.md', - '', - message: 'Add README.md', - branch_name: 'master' - ) - end -end diff --git a/app/services/delete_branch_service.rb b/app/services/delete_branch_service.rb deleted file mode 100644 index fd41ce54486..00000000000 --- a/app/services/delete_branch_service.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -class DeleteBranchService < BaseService - def execute(branch_name) - repository = project.repository - branch = repository.find_branch(branch_name) - - unless current_user.can?(:push_code, project) - return ServiceResponse.error( - message: 'You dont have push access to repo', - http_status: 405) - end - - unless branch - return ServiceResponse.error( - message: 'No such branch', - http_status: 404) - end - - if repository.rm_branch(current_user, branch_name) - ServiceResponse.success(message: 'Branch was deleted') - else - ServiceResponse.error( - message: 'Failed to remove branch', - http_status: 400) - end - rescue Gitlab::Git::PreReceiveError => ex - ServiceResponse.error(message: ex.message, http_status: 400) - end -end diff --git a/app/services/delete_merged_branches_service.rb b/app/services/delete_merged_branches_service.rb deleted file mode 100644 index 80de897e94b..00000000000 --- a/app/services/delete_merged_branches_service.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -class DeleteMergedBranchesService < BaseService - def async_execute - DeleteMergedBranchesWorker.perform_async(project.id, current_user.id) - end - - def execute - raise Gitlab::Access::AccessDeniedError unless can?(current_user, :push_code, project) - - branches = project.repository.merged_branch_names - # Prevent deletion of branches relevant to open merge requests - branches -= merge_request_branch_names - # Prevent deletion of protected branches - branches = branches.reject { |branch| ProtectedBranch.protected?(project, branch) } - - branches.each do |branch| - DeleteBranchService.new(project, current_user).execute(branch) - end - end - - private - - # rubocop: disable CodeReuse/ActiveRecord - def merge_request_branch_names - # reorder(nil) is necessary for SELECT DISTINCT because default scope adds an ORDER BY - source_names = project.origin_merge_requests.opened.reorder(nil).distinct.pluck(:source_branch) - target_names = project.merge_requests.opened.reorder(nil).distinct.pluck(:target_branch) - (source_names + target_names).uniq - end - # rubocop: enable CodeReuse/ActiveRecord -end diff --git a/app/services/merge_requests/create_from_issue_service.rb b/app/services/merge_requests/create_from_issue_service.rb index 200a34cae04..95fb99d3e7a 100644 --- a/app/services/merge_requests/create_from_issue_service.rb +++ b/app/services/merge_requests/create_from_issue_service.rb @@ -19,7 +19,7 @@ module MergeRequests return error('Not allowed to create merge request') unless can_create_merge_request? return error('Invalid issue iid') unless @issue_iid.present? && issue.present? - result = CreateBranchService.new(target_project, current_user).execute(branch_name, ref) + result = ::Branches::CreateService.new(target_project, current_user).execute(branch_name, ref) return result if result[:status] == :error new_merge_request = create(merge_request) diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 2eef3eed804..4a109fe4e16 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -99,7 +99,7 @@ module MergeRequests log_info("Post merge finished on JID #{merge_jid} with state #{state}") if delete_source_branch? - DeleteBranchService.new(@merge_request.source_project, branch_deletion_user) + ::Branches::DeleteService.new(@merge_request.source_project, branch_deletion_user) .execute(merge_request.source_branch) end end diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb index e7bcca1a38d..55f888d5664 100644 --- a/app/services/todo_service.rb +++ b/app/services/todo_service.rb @@ -179,6 +179,14 @@ class TodoService mark_todos_as_done(todos, current_user) end + def mark_todo_as_done(todo, current_user) + return if todo.done? + + todo.update(state: :done) + + current_user.update_todos_count_cache + end + # When user marks some todos as pending def mark_todos_as_pending(todos, current_user) update_todos_state(todos, current_user, :pending) diff --git a/app/services/validate_new_branch_service.rb b/app/services/validate_new_branch_service.rb deleted file mode 100644 index 3f4a59e5cee..00000000000 --- a/app/services/validate_new_branch_service.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require_relative 'base_service' - -class ValidateNewBranchService < BaseService - def execute(branch_name, force: false) - valid_branch = Gitlab::GitRefValidator.validate(branch_name) - - unless valid_branch - return error('Branch name is invalid') - end - - if project.repository.branch_exists?(branch_name) && !force - return error('Branch already exists') - end - - success - rescue Gitlab::Git::PreReceiveError => ex - error(ex.message) - end -end diff --git a/app/views/instance_statistics/conversational_development_index/_callout.html.haml b/app/views/instance_statistics/dev_ops_score/_callout.html.haml index 15e31fa3d9c..61f998424f2 100644 --- a/app/views/instance_statistics/conversational_development_index/_callout.html.haml +++ b/app/views/instance_statistics/dev_ops_score/_callout.html.haml @@ -1,5 +1,5 @@ .prepend-top-default -.user-callout{ data: { uid: 'convdev_intro_callout_dismissed' } } +.user-callout{ data: { uid: 'dev_ops_score_intro_callout_dismissed' } } .bordered-box.landing.content-block %button.btn.btn-default.close.js-close-callout{ type: 'button', 'aria-label' => _('Dismiss ConvDev introduction') } @@ -9,5 +9,5 @@ = _('Introducing Your Conversational Development Index') %p = _('Your Conversational Development Index gives an overview of how you are using GitLab from a feature perspective. View how you compare with other organizations, discover features you are not using, and learn best practices through blog posts and white papers.') - .svg-container.devops - = custom_icon('convdev_overview') + .svg-container.convdev + = custom_icon('dev_ops_score_overview') diff --git a/app/views/instance_statistics/conversational_development_index/_card.html.haml b/app/views/instance_statistics/dev_ops_score/_card.html.haml index c63bd96a175..c63bd96a175 100644 --- a/app/views/instance_statistics/conversational_development_index/_card.html.haml +++ b/app/views/instance_statistics/dev_ops_score/_card.html.haml diff --git a/app/views/instance_statistics/conversational_development_index/_disabled.html.haml b/app/views/instance_statistics/dev_ops_score/_disabled.html.haml index ddcbdf6dd27..da27ea17b61 100644 --- a/app/views/instance_statistics/conversational_development_index/_disabled.html.haml +++ b/app/views/instance_statistics/dev_ops_score/_disabled.html.haml @@ -1,6 +1,6 @@ .container.devops-empty .col-sm-12.justify-content-center.text-center - = custom_icon('convdev_no_index') + = custom_icon('dev_ops_score_no_index') %h4= _('Usage ping is not enabled') - if !current_user.admin? %p diff --git a/app/views/instance_statistics/conversational_development_index/_no_data.html.haml b/app/views/instance_statistics/dev_ops_score/_no_data.html.haml index 2031bced4fc..54598244039 100644 --- a/app/views/instance_statistics/conversational_development_index/_no_data.html.haml +++ b/app/views/instance_statistics/dev_ops_score/_no_data.html.haml @@ -1,7 +1,7 @@ .container.devops-empty .col-sm-12.justify-content-center.text-center - = custom_icon('convdev_no_data') + = custom_icon('dev_ops_score_no_data') %h4= _('Data is still calculating...') %p = _('In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index.') - = link_to _('Learn more'), help_page_path('user/instance_statistics/convdev'), target: '_blank' + = link_to _('Learn more'), help_page_path('user/instance_statistics/dev_ops_score'), target: '_blank' diff --git a/app/views/instance_statistics/conversational_development_index/index.html.haml b/app/views/instance_statistics/dev_ops_score/index.html.haml index f9a40152380..bd457f4740a 100644 --- a/app/views/instance_statistics/conversational_development_index/index.html.haml +++ b/app/views/instance_statistics/dev_ops_score/index.html.haml @@ -2,7 +2,7 @@ - usage_ping_enabled = Gitlab::CurrentSettings.usage_ping_enabled .container - - if usage_ping_enabled && show_callout?('convdev_intro_callout_dismissed') + - if usage_ping_enabled && show_callout?('dev_ops_score_intro_callout_dismissed') = render 'callout' .prepend-top-default @@ -19,7 +19,7 @@ = _('index') %br = _('score') - = link_to icon('question-circle', 'aria-hidden' => 'true'), help_page_path('user/instance_statistics/convdev') + = link_to icon('question-circle', 'aria-hidden' => 'true'), help_page_path('user/instance_statistics/dev_ops_score') .devops-cards.board-card-container - @metric.cards.each do |card| diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index d339751848b..9a839765286 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -48,7 +48,7 @@ %li.dropdown = render_if_exists 'dashboard/nav_link_list' - if can?(current_user, :read_instance_statistics) - = nav_link(controller: [:conversational_development_index, :cohorts]) do + = nav_link(controller: [:dev_ops_score, :cohorts]) do = link_to instance_statistics_root_path do = _('Instance Statistics') - if current_user.admin? diff --git a/app/views/layouts/nav/sidebar/_instance_statistics.html.haml b/app/views/layouts/nav/sidebar/_instance_statistics.html.haml index 57180f27146..6a5f727bb48 100644 --- a/app/views/layouts/nav/sidebar/_instance_statistics.html.haml +++ b/app/views/layouts/nav/sidebar/_instance_statistics.html.haml @@ -6,15 +6,15 @@ = sprite_icon('chart', size: 24) .sidebar-context-title= _('Instance Statistics') %ul.sidebar-top-level-items - = nav_link(controller: :conversational_development_index) do - = link_to instance_statistics_conversational_development_index_index_path do + = nav_link(controller: :dev_ops_score) do + = link_to instance_statistics_dev_ops_score_index_path do .nav-icon-container = sprite_icon('comment') %span.nav-item-name = _('ConvDev Index') %ul.sidebar-sub-level-items.is-fly-out-only - = nav_link(controller: :conversational_development_index, html_options: { class: "fly-out-top-item" } ) do - = link_to instance_statistics_conversational_development_index_index_path do + = nav_link(controller: :dev_ops_score, html_options: { class: "fly-out-top-item" } ) do + = link_to instance_statistics_dev_ops_score_index_path do %strong.fly-out-top-item-name = _('ConvDev Index') diff --git a/app/views/shared/icons/_convdev_no_data.svg b/app/views/shared/icons/_dev_ops_score_no_data.svg index ed32b2333e7..ed32b2333e7 100644 --- a/app/views/shared/icons/_convdev_no_data.svg +++ b/app/views/shared/icons/_dev_ops_score_no_data.svg diff --git a/app/views/shared/icons/_convdev_no_index.svg b/app/views/shared/icons/_dev_ops_score_no_index.svg index 95c00e81d10..95c00e81d10 100644 --- a/app/views/shared/icons/_convdev_no_index.svg +++ b/app/views/shared/icons/_dev_ops_score_no_index.svg diff --git a/app/views/shared/icons/_convdev_overview.svg b/app/views/shared/icons/_dev_ops_score_overview.svg index 2f31113bad7..2f31113bad7 100644 --- a/app/views/shared/icons/_convdev_overview.svg +++ b/app/views/shared/icons/_dev_ops_score_overview.svg diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml index b324f35c338..6e50b31fd71 100644 --- a/app/views/shared/milestones/_milestone.html.haml +++ b/app/views/shared/milestones/_milestone.html.haml @@ -43,8 +43,9 @@ .col-sm-4.milestone-progress = milestone_progress_bar(milestone) = link_to pluralize(milestone.total_issues_count(current_user), 'Issue'), issues_path - · - = link_to pluralize(milestone.merge_requests_visible_to_user(current_user).size, 'Merge Request'), merge_requests_path + - if milestone.merge_requests_enabled? + · + = link_to pluralize(milestone.merge_requests_visible_to_user(current_user).size, 'Merge Request'), merge_requests_path .float-lg-right.light #{milestone.percent_complete(current_user)}% complete .col-sm-2 .milestone-actions.d-flex.justify-content-sm-start.justify-content-md-end diff --git a/app/views/shared/milestones/_sidebar.html.haml b/app/views/shared/milestones/_sidebar.html.haml index b6656e6283c..fbbcc4f3e68 100644 --- a/app/views/shared/milestones/_sidebar.html.haml +++ b/app/views/shared/milestones/_sidebar.html.haml @@ -105,38 +105,39 @@ = render_if_exists 'shared/milestones/weight', milestone: milestone - .block.merge-requests - .sidebar-collapsed-icon.has-tooltip{ title: milestone_merge_requests_tooltip_text(milestone), data: { container: 'body', html: 'true', placement: 'left', boundary: 'viewport' } } - %strong - = custom_icon('mr_bold') - %span= milestone.merge_requests.count - .title.hide-collapsed - Merge requests - %span.badge.badge-pill= milestone.merge_requests.count - .value.hide-collapsed.bold - - if !project || can?(current_user, :read_merge_request, project) - %span.milestone-stat - = link_to milestones_browse_issuables_path(milestone, type: :merge_requests) do + - if milestone.merge_requests_enabled? + .block.merge-requests + .sidebar-collapsed-icon.has-tooltip{ title: milestone_merge_requests_tooltip_text(milestone), data: { container: 'body', html: 'true', placement: 'left', boundary: 'viewport' } } + %strong + = custom_icon('mr_bold') + %span= milestone.merge_requests.count + .title.hide-collapsed + Merge requests + %span.badge.badge-pill= milestone.merge_requests.count + .value.hide-collapsed.bold + - if !project || can?(current_user, :read_merge_request, project) + %span.milestone-stat + = link_to milestones_browse_issuables_path(milestone, type: :merge_requests) do + Open: + = milestone.merge_requests.opened.count + %span.milestone-stat + = link_to milestones_browse_issuables_path(milestone, type: :merge_requests, state: 'closed') do + Closed: + = milestone.merge_requests.closed.count + %span.milestone-stat + = link_to milestones_browse_issuables_path(milestone, type: :merge_requests, state: 'merged') do + Merged: + = milestone.merge_requests.merged.count + - else + %span.milestone-stat Open: = milestone.merge_requests.opened.count - %span.milestone-stat - = link_to milestones_browse_issuables_path(milestone, type: :merge_requests, state: 'closed') do + %span.milestone-stat Closed: = milestone.merge_requests.closed.count - %span.milestone-stat - = link_to milestones_browse_issuables_path(milestone, type: :merge_requests, state: 'merged') do + %span.milestone-stat Merged: = milestone.merge_requests.merged.count - - else - %span.milestone-stat - Open: - = milestone.merge_requests.opened.count - %span.milestone-stat - Closed: - = milestone.merge_requests.closed.count - %span.milestone-stat - Merged: - = milestone.merge_requests.merged.count - if project - recent_releases, total_count, more_count = recent_releases_with_counts(milestone) diff --git a/app/views/shared/milestones/_tabs.html.haml b/app/views/shared/milestones/_tabs.html.haml index f718c5767d1..538ebe79641 100644 --- a/app/views/shared/milestones/_tabs.html.haml +++ b/app/views/shared/milestones/_tabs.html.haml @@ -6,10 +6,11 @@ = link_to '#tab-issues', class: 'nav-link active', data: { toggle: 'tab', show: '.tab-issues-buttons' } do = _('Issues') %span.badge.badge-pill= milestone.issues_visible_to_user(current_user).size - %li.nav-item - = link_to '#tab-merge-requests', class: 'nav-link', data: { toggle: 'tab', endpoint: milestone_tab_path(milestone, 'merge_requests') } do - = _('Merge Requests') - %span.badge.badge-pill= milestone.merge_requests_visible_to_user(current_user).size + - if milestone.merge_requests_enabled? + %li.nav-item + = link_to '#tab-merge-requests', class: 'nav-link', data: { toggle: 'tab', endpoint: milestone_tab_path(milestone, 'merge_requests') } do + = _('Merge Requests') + %span.badge.badge-pill= milestone.merge_requests_visible_to_user(current_user).size %li.nav-item = link_to '#tab-participants', class: 'nav-link', data: { toggle: 'tab', endpoint: milestone_tab_path(milestone, 'participants') } do = _('Participants') @@ -26,9 +27,10 @@ .tab-content.milestone-content .tab-pane.active#tab-issues{ data: { sort_endpoint: (sort_issues_project_milestone_path(@project, @milestone) if @project && current_user) } } = render 'shared/milestones/issues_tab', issues: issues, show_project_name: show_project_name, show_full_project_name: show_full_project_name - .tab-pane#tab-merge-requests - -# loaded async - = render "shared/milestones/tab_loading" + - if milestone.merge_requests_enabled? + .tab-pane#tab-merge-requests + -# loaded async + = render "shared/milestones/tab_loading" .tab-pane#tab-participants -# loaded async = render "shared/milestones/tab_loading" diff --git a/app/workers/delete_merged_branches_worker.rb b/app/workers/delete_merged_branches_worker.rb index 44b3db30d0d..f3d86233c1b 100644 --- a/app/workers/delete_merged_branches_worker.rb +++ b/app/workers/delete_merged_branches_worker.rb @@ -15,7 +15,7 @@ class DeleteMergedBranchesWorker user = User.find(user_id) begin - DeleteMergedBranchesService.new(project, user).execute + ::Branches::DeleteMergedService.new(project, user).execute rescue Gitlab::Access::AccessDeniedError return end |