diff options
Diffstat (limited to 'app/models')
29 files changed, 267 insertions, 137 deletions
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 253e213af81..80bda7f22ff 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -261,6 +261,7 @@ class ApplicationSetting < ActiveRecord::Base { after_sign_up_text: nil, akismet_enabled: false, + authorized_keys_enabled: true, # TODO default to false if the instance is configured to use AuthorizedKeysCommand container_registry_token_expire_delay: 5, default_artifacts_expire_in: '30 days', default_branch_protection: Settings.gitlab['default_branch_protection'], @@ -417,6 +418,7 @@ class ApplicationSetting < ActiveRecord::Base super(group_full_path) Gitlab::PerformanceBar.expire_allowed_user_ids_cache end + return end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 83fe23606d1..6012dbba1b9 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -79,7 +79,7 @@ module Ci before_save :ensure_token before_destroy { unscoped_project } - after_create do |build| + after_create unless: :importing? do |build| run_after_commit { BuildHooksWorker.perform_async(build.id) } end @@ -461,7 +461,14 @@ module Ci end def cache - [options[:cache]] + cache = options[:cache] + + if cache && project.jobs_cache_index + cache = cache.merge( + key: "#{cache[:key]}:#{project.jobs_cache_index}") + end + + [cache] end def credentials diff --git a/app/models/ci/pipeline_schedule.rb b/app/models/ci/pipeline_schedule.rb index 10ead6b6d3b..b6abc3d7681 100644 --- a/app/models/ci/pipeline_schedule.rb +++ b/app/models/ci/pipeline_schedule.rb @@ -2,8 +2,9 @@ module Ci class PipelineSchedule < ActiveRecord::Base extend Gitlab::Ci::Model include Importable + include IgnorableColumn - acts_as_paranoid + ignore_column :deleted_at belongs_to :project belongs_to :owner, class_name: 'User' diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb index b5290bcaf53..aa065e33739 100644 --- a/app/models/ci/trigger.rb +++ b/app/models/ci/trigger.rb @@ -1,8 +1,9 @@ module Ci class Trigger < ActiveRecord::Base extend Gitlab::Ci::Model + include IgnorableColumn - acts_as_paranoid + ignore_column :deleted_at belongs_to :project belongs_to :owner, class_name: "User" diff --git a/app/models/commit.rb b/app/models/commit.rb index 2be07ca7d3c..39d7f5b159d 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -371,7 +371,7 @@ class Commit # # Returns a symbol def uri_type(path) - entry = @raw.tree.path(path) + entry = @raw.rugged_tree_entry(path) if entry[:type] == :blob blob = ::Blob.decorate(Gitlab::Git::Blob.new(name: entry[:name]), @project) blob.image? || blob.video? ? :raw : :blob diff --git a/app/models/concerns/deployment_platform.rb b/app/models/concerns/deployment_platform.rb new file mode 100644 index 00000000000..89d0474a596 --- /dev/null +++ b/app/models/concerns/deployment_platform.rb @@ -0,0 +1,48 @@ +module DeploymentPlatform + def deployment_platform + @deployment_platform ||= + find_cluster_platform_kubernetes || + find_kubernetes_service_integration || + build_cluster_and_deployment_platform + end + + private + + def find_cluster_platform_kubernetes + clusters.find_by(enabled: true)&.platform_kubernetes + end + + def find_kubernetes_service_integration + services.deployment.reorder(nil).find_by(active: true) + end + + def build_cluster_and_deployment_platform + return unless kubernetes_service_template + + cluster = ::Clusters::Cluster.create(cluster_attributes_from_service_template) + cluster.platform_kubernetes if cluster.persisted? + end + + def kubernetes_service_template + @kubernetes_service_template ||= KubernetesService.active.find_by_template + end + + def cluster_attributes_from_service_template + { + name: 'kubernetes-template', + projects: [self], + provider_type: :user, + platform_type: :kubernetes, + platform_kubernetes_attributes: platform_kubernetes_attributes_from_service_template + } + end + + def platform_kubernetes_attributes_from_service_template + { + api_url: kubernetes_service_template.api_url, + ca_pem: kubernetes_service_template.ca_pem, + token: kubernetes_service_template.token, + namespace: kubernetes_service_template.namespace + } + end +end diff --git a/app/models/concerns/internal_id.rb b/app/models/concerns/internal_id.rb index a3d0ac8d862..01079fb8bd6 100644 --- a/app/models/concerns/internal_id.rb +++ b/app/models/concerns/internal_id.rb @@ -10,7 +10,6 @@ module InternalId if iid.blank? parent = project || group records = parent.public_send(self.class.name.tableize) # rubocop:disable GitlabSecurity/PublicSend - records = records.with_deleted if self.paranoid? max_iid = records.maximum(:iid) self.iid = max_iid.to_i + 1 diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 5ca4a7086cb..7049f340c9d 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -96,7 +96,7 @@ module Issuable strip_attributes :title - after_save :record_metrics, unless: :imported? + after_save :ensure_metrics, unless: :imported? # We want to use optimistic lock for cases when only title or description are involved # http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html @@ -314,6 +314,7 @@ module Issuable includes = [] includes << :author unless notes.authors_loaded? includes << :award_emoji unless notes.award_emojis_loaded? + if includes.any? notes.includes(includes) else @@ -335,11 +336,6 @@ module Issuable false end - def record_metrics - metrics = self.metrics || create_metrics - metrics.record! - end - ## # Override in issuable specialization # @@ -347,6 +343,10 @@ module Issuable false end + def ensure_metrics + self.metrics || create_metrics + end + ## # Overriden in MergeRequest # diff --git a/app/models/concerns/loaded_in_group_list.rb b/app/models/concerns/loaded_in_group_list.rb index dcb3b2b5ff3..935e9d10133 100644 --- a/app/models/concerns/loaded_in_group_list.rb +++ b/app/models/concerns/loaded_in_group_list.rb @@ -25,6 +25,7 @@ module LoadedInGroupList base_count = projects.project(Arel.star.count.as('preloaded_project_count')) .where(projects[:namespace_id].eq(namespaces[:id])) + if archived == 'only' base_count.where(projects[:archived].eq(true)) elsif Gitlab::Utils.to_boolean(archived) diff --git a/app/models/concerns/relative_positioning.rb b/app/models/concerns/relative_positioning.rb index 835f26aa57b..afacdb8cb12 100644 --- a/app/models/concerns/relative_positioning.rb +++ b/app/models/concerns/relative_positioning.rb @@ -10,12 +10,12 @@ module RelativePositioning after_save :save_positionable_neighbours end - def project_ids - [project.id] + def min_relative_position + self.class.in_parents(parent_ids).minimum(:relative_position) end def max_relative_position - self.class.in_projects(project_ids).maximum(:relative_position) + self.class.in_parents(parent_ids).maximum(:relative_position) end def prev_relative_position @@ -23,7 +23,7 @@ module RelativePositioning if self.relative_position prev_pos = self.class - .in_projects(project_ids) + .in_parents(parent_ids) .where('relative_position < ?', self.relative_position) .maximum(:relative_position) end @@ -36,7 +36,7 @@ module RelativePositioning if self.relative_position next_pos = self.class - .in_projects(project_ids) + .in_parents(parent_ids) .where('relative_position > ?', self.relative_position) .minimum(:relative_position) end @@ -63,7 +63,7 @@ module RelativePositioning pos_after = before.next_relative_position if before.shift_after? - issue_to_move = self.class.in_projects(project_ids).find_by!(relative_position: pos_after) + issue_to_move = self.class.in_parents(parent_ids).find_by!(relative_position: pos_after) issue_to_move.move_after @positionable_neighbours = [issue_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables @@ -78,7 +78,7 @@ module RelativePositioning pos_before = after.prev_relative_position if after.shift_before? - issue_to_move = self.class.in_projects(project_ids).find_by!(relative_position: pos_before) + issue_to_move = self.class.in_parents(parent_ids).find_by!(relative_position: pos_before) issue_to_move.move_before @positionable_neighbours = [issue_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables @@ -92,6 +92,10 @@ module RelativePositioning self.relative_position = position_between(max_relative_position || START_POSITION, MAX_POSITION) end + def move_to_start + self.relative_position = position_between(min_relative_position || START_POSITION, MIN_POSITION) + end + # Indicates if there is an issue that should be shifted to free the place def shift_after? next_pos = next_relative_position diff --git a/app/models/concerns/storage/legacy_namespace.rb b/app/models/concerns/storage/legacy_namespace.rb index b3020484738..99dbd4fbacf 100644 --- a/app/models/concerns/storage/legacy_namespace.rb +++ b/app/models/concerns/storage/legacy_namespace.rb @@ -34,6 +34,8 @@ module Storage # So we basically we mute exceptions in next actions begin send_update_instructions + write_projects_repository_config + true rescue # Returning false does not rollback after_* transaction but gives diff --git a/app/models/diff_discussion.rb b/app/models/diff_discussion.rb index d67b16584a4..bd6af622bfb 100644 --- a/app/models/diff_discussion.rb +++ b/app/models/diff_discussion.rb @@ -23,8 +23,13 @@ class DiffDiscussion < Discussion def merge_request_version_params return unless for_merge_request? + version_params = get_params + + return version_params unless on_merge_request_commit? && commit_id + + version_params ||= {} version_params.tap do |params| - params[:commit_id] = commit_id if on_merge_request_commit? + params[:commit_id] = commit_id end end @@ -37,7 +42,7 @@ class DiffDiscussion < Discussion private - def version_params + def get_params return {} if active? noteable.version_params_for(position.diff_refs) diff --git a/app/models/event.rb b/app/models/event.rb index 0997b056c6a..8a79100de5a 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -48,7 +48,18 @@ class Event < ActiveRecord::Base belongs_to :author, class_name: "User" belongs_to :project - belongs_to :target, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations + + belongs_to :target, -> { + # If the association for "target" defines an "author" association we want to + # eager-load this so Banzai & friends don't end up performing N+1 queries to + # get the authors of notes, issues, etc. + if reflections['events'].active_record.reflect_on_association(:author) + includes(:author) + else + self + end + }, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations + has_one :push_event_payload # Callbacks diff --git a/app/models/issue.rb b/app/models/issue.rb index dc64888b6fc..93628b456f2 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -12,7 +12,7 @@ class Issue < ActiveRecord::Base include ThrottledTouch include IgnorableColumn - ignore_column :assignee_id, :branch_name + ignore_column :assignee_id, :branch_name, :deleted_at DueDateStruct = Struct.new(:title, :name).freeze NoDueDate = DueDateStruct.new('No Due Date', '0').freeze @@ -35,6 +35,8 @@ class Issue < ActiveRecord::Base validates :project, presence: true + alias_attribute :parent_ids, :project_id + scope :in_projects, ->(project_ids) { where(project_id: project_ids) } scope :assigned, -> { where('EXISTS (SELECT TRUE FROM issue_assignees WHERE issue_id = issues.id)') } @@ -76,7 +78,9 @@ class Issue < ActiveRecord::Base end end - acts_as_paranoid + class << self + alias_method :in_parents, :in_projects + end def self.reference_prefix '#' @@ -276,6 +280,11 @@ class Issue < ActiveRecord::Base private + def ensure_metrics + super + metrics.record! + end + # Returns `true` if the given User can read the current Issue. # # This method duplicates the same check of issue_policy.rb diff --git a/app/models/label.rb b/app/models/label.rb index b5bfa6ea2dd..7538f2d8718 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -132,6 +132,7 @@ class Label < ActiveRecord::Base else priorities.find_by(project: project) end + priority.try(:priority) end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index c39789b047d..2669d2a6ff3 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -11,7 +11,8 @@ class MergeRequest < ActiveRecord::Base include Gitlab::Utils::StrongMemoize ignore_column :locked_at, - :ref_fetched + :ref_fetched, + :deleted_at belongs_to :target_project, class_name: "Project" belongs_to :source_project, class_name: "Project" @@ -150,12 +151,17 @@ class MergeRequest < ActiveRecord::Base after_save :keep_around_commit - acts_as_paranoid - def self.reference_prefix '!' end + def rebase_in_progress? + # The source project can be deleted + return false unless source_project + + source_project.repository.rebase_in_progress?(id) + end + # Use this method whenever you need to make sure the head_pipeline is synced with the # branch head commit, for example checking if a merge request can be merged. # For more information check: https://gitlab.com/gitlab-org/gitlab-ce/issues/40004 @@ -607,7 +613,7 @@ class MergeRequest < ActiveRecord::Base check_if_can_be_merged - can_be_merged? + can_be_merged? && !should_be_rebased? end def mergeable_state?(skip_ci_check: false) @@ -787,6 +793,7 @@ class MergeRequest < ActiveRecord::Base if !include_description && closes_issues_references.present? message << "Closes #{closes_issues_references.to_sentence}" end + message << "#{description}" if include_description && description.present? message << "See merge request #{to_reference(full: true)}" diff --git a/app/models/merge_request/metrics.rb b/app/models/merge_request/metrics.rb index cdc408738be..9e660eccd86 100644 --- a/app/models/merge_request/metrics.rb +++ b/app/models/merge_request/metrics.rb @@ -1,12 +1,6 @@ class MergeRequest::Metrics < ActiveRecord::Base belongs_to :merge_request belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :pipeline_id - - def record! - if merge_request.merged? && self.merged_at.blank? - self.merged_at = Time.now - end - - self.save - end + belongs_to :latest_closed_by, class_name: 'User' + belongs_to :merged_by, class_name: 'User' end diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index e35de9b97ee..afab72930c1 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -49,6 +49,7 @@ class MergeRequestDiff < ActiveRecord::Base ensure_commit_shas save_commits save_diffs + save keep_around_commits end @@ -56,7 +57,6 @@ class MergeRequestDiff < ActiveRecord::Base self.start_commit_sha ||= merge_request.target_branch_sha self.head_commit_sha ||= merge_request.source_branch_sha self.base_commit_sha ||= find_base_sha - save end # Override head_commit_sha to keep compatibility with merge request diff @@ -195,7 +195,7 @@ class MergeRequestDiff < ActiveRecord::Base end def commits_count - merge_request_diff_commits.size + super || merge_request_diff_commits.size end private @@ -264,13 +264,16 @@ class MergeRequestDiff < ActiveRecord::Base new_attributes[:state] = :overflow if diff_collection.overflow? end - update(new_attributes) + assign_attributes(new_attributes) end def save_commits MergeRequestDiffCommit.create_bulk(self.id, compare.commits.reverse) - merge_request_diff_commits.reload + # merge_request_diff_commits.reload is preferred way to reload associated + # objects but it returns cached result for some reason in this case + commits = merge_request_diff_commits(true) + self.commits_count = commits.size end def repository diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 0ff169d4531..37a7417cafc 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -1,6 +1,4 @@ class Namespace < ActiveRecord::Base - acts_as_paranoid without_default_scope: true - include CacheMarkdownField include Sortable include Gitlab::ShellAdapter @@ -10,6 +8,9 @@ class Namespace < ActiveRecord::Base include AfterCommitQueue include Storage::LegacyNamespace include Gitlab::SQL::Pattern + include IgnorableColumn + + ignore_column :deleted_at # Prevent users from creating unreasonably deep level of nesting. # The number 20 was taken based on maximum nesting level of @@ -221,12 +222,6 @@ class Namespace < ActiveRecord::Base has_parent? end - def soft_delete_without_removing_associations - # We can't use paranoia's `#destroy` since this will hard-delete projects. - # Project uses `pending_delete` instead of the acts_as_paranoia gem. - self.deleted_at = Time.now - end - private def refresh_access_of_projects_invited_groups @@ -268,4 +263,11 @@ class Namespace < ActiveRecord::Base def namespace_previously_created_with_same_path? RedirectRoute.permanent.exists?(path: path) end + + def write_projects_repository_config + all_projects.find_each do |project| + project.expires_full_path_cache # we need to clear cache to validate renames correctly + project.write_repository_config + end + end end diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb index aec7b01e23a..c351d2012c6 100644 --- a/app/models/network/graph.rb +++ b/app/models/network/graph.rb @@ -224,6 +224,7 @@ module Network space_base = parents.first.space end end + space_base end diff --git a/app/models/notification_recipient.rb b/app/models/notification_recipient.rb index 183e098d819..ab5a96209c7 100644 --- a/app/models/notification_recipient.rb +++ b/app/models/notification_recipient.rb @@ -9,6 +9,7 @@ class NotificationRecipient group: nil, skip_read_ability: false ) + unless NotificationSetting.levels.key?(type) || type == :subscription raise ArgumentError, "invalid type: #{type.inspect}" end diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb index 8de42ff9d2e..d8bf54e0c40 100644 --- a/app/models/pages_domain.rb +++ b/app/models/pages_domain.rb @@ -27,7 +27,7 @@ class PagesDomain < ActiveRecord::Base def url return unless domain - if certificate + if certificate.present? "https://#{domain}" else "http://#{domain}" diff --git a/app/models/project.rb b/app/models/project.rb index 6678733e43e..029f2da2e4e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -19,6 +19,7 @@ class Project < ActiveRecord::Base include Routable include GroupDescendant include Gitlab::SQL::Pattern + include DeploymentPlatform extend Gitlab::ConfigHelper extend Gitlab::CurrentSettings @@ -632,6 +633,7 @@ class Project < ActiveRecord::Base project_import_data.data ||= {} project_import_data.data = project_import_data.data.merge(data) end + if credentials project_import_data.credentials ||= {} project_import_data.credentials = project_import_data.credentials.merge(credentials) @@ -639,7 +641,7 @@ class Project < ActiveRecord::Base end def import? - external_import? || forked? || gitlab_project_import? + external_import? || forked? || gitlab_project_import? || bare_repository_import? end def no_import? @@ -679,6 +681,10 @@ class Project < ActiveRecord::Base Gitlab::UrlSanitizer.new(import_url).masked_url end + def bare_repository_import? + import_type == 'bare_repository' + end + def gitlab_project_import? import_type == 'gitlab_project' end @@ -900,12 +906,6 @@ class Project < ActiveRecord::Base @ci_service ||= ci_services.reorder(nil).find_by(active: true) end - # TODO: This will be extended for multiple enviroment clusters - def deployment_platform - @deployment_platform ||= clusters.find_by(enabled: true)&.platform_kubernetes - @deployment_platform ||= services.where(category: :deployment).reorder(nil).find_by(active: true) - end - def monitoring_services services.where(category: :monitoring) end @@ -988,10 +988,6 @@ class Project < ActiveRecord::Base false end - def repo - repository.rugged - end - def url_to_repo gitlab_shell.url_to_repo(full_path) end @@ -1154,7 +1150,7 @@ class Project < ActiveRecord::Base def change_head(branch) if repository.branch_exists?(branch) repository.before_change_head - repository.write_ref('HEAD', "refs/heads/#{branch}") + repository.raw_repository.write_ref('HEAD', "refs/heads/#{branch}", shell: false) repository.copy_gitattributes(branch) repository.after_change_head reload_default_branch @@ -1416,6 +1412,8 @@ class Project < ActiveRecord::Base end def after_rename_repo + write_repository_config + path_before_change = previous_changes['path'].first # We need to check if project had been rolled out to move resource to hashed storage or not and decide @@ -1428,6 +1426,16 @@ class Project < ActiveRecord::Base Gitlab::PagesTransfer.new.rename_project(path_before_change, self.path, namespace.full_path) end + def write_repository_config(gl_full_path: full_path) + # We'd need to keep track of project full path otherwise directory tree + # created with hashed storage enabled cannot be usefully imported using + # the import rake task. + repository.rugged.config['gitlab.fullpath'] = gl_full_path + rescue Gitlab::Git::Repository::NoRepository => e + Rails.logger.error("Error writing to .git/config for project #{full_path} (#{id}): #{e.message}.") + nil + end + def rename_repo_notify! send_move_instructions(full_path_was) expires_full_path_cache @@ -1443,6 +1451,7 @@ class Project < ActiveRecord::Base import_finish remove_import_jid update_project_counter_caches + after_create_default_branch end def update_project_counter_caches @@ -1456,6 +1465,27 @@ class Project < ActiveRecord::Base end end + def after_create_default_branch + return unless default_branch + + # Ensure HEAD points to the default branch in case it is not master + change_head(default_branch) + + if current_application_settings.default_branch_protection != Gitlab::Access::PROTECTION_NONE && !ProtectedBranch.protected?(self, default_branch) + params = { + name: default_branch, + push_access_levels_attributes: [{ + access_level: current_application_settings.default_branch_protection == Gitlab::Access::PROTECTION_DEV_CAN_PUSH ? Gitlab::Access::DEVELOPER : Gitlab::Access::MASTER + }], + merge_access_levels_attributes: [{ + access_level: current_application_settings.default_branch_protection == Gitlab::Access::PROTECTION_DEV_CAN_MERGE ? Gitlab::Access::DEVELOPER : Gitlab::Access::MASTER + }] + } + + ProtectedBranches::CreateService.new(self, creator, params).execute(skip_authorization: true) + end + end + def remove_import_jid return unless import_jid diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 768f0a7472e..bfe7ac29c18 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -110,6 +110,7 @@ class HipchatService < Service message = "" message << "#{push[:user_name]} " + if Gitlab::Git.blank_ref?(before) message << "pushed new #{ref_type} <a href=\""\ "#{project_url}/commits/#{CGI.escape(ref)}\">#{ref}</a>"\ diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb index b82567ce2b3..c72b01b64af 100644 --- a/app/models/project_services/kubernetes_service.rb +++ b/app/models/project_services/kubernetes_service.rb @@ -31,6 +31,7 @@ class KubernetesService < DeploymentService before_validation :enforce_namespace_to_lower_case + validate :deprecation_validation, unless: :template? validates :namespace, allow_blank: true, length: 1..63, @@ -145,6 +146,17 @@ class KubernetesService < DeploymentService @kubeclient ||= build_kubeclient! end + def deprecated? + !active + end + + def deprecation_message + content = <<-MESSAGE.strip_heredoc + Kubernetes service integration has been deprecated. #{deprecated_message_content} your clusters using the new <a href=\'#{Gitlab::Routing.url_helpers.project_clusters_path(project)}'/>Clusters</a> page + MESSAGE + content.html_safe + end + TEMPLATE_PLACEHOLDER = 'Kubernetes namespace'.freeze private @@ -226,4 +238,20 @@ class KubernetesService < DeploymentService def enforce_namespace_to_lower_case self.namespace = self.namespace&.downcase end + + def deprecation_validation + return if active_changed?(from: true, to: false) + + if deprecated? + errors[:base] << deprecation_message + end + end + + def deprecated_message_content + if active? + "Your cluster information on this page is still editable, but you are advised to disable and reconfigure" + else + "Fields on this page are now uneditable, you can configure" + end + end end diff --git a/app/models/repository.rb b/app/models/repository.rb index b1fd981965c..d27212b2058 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -4,6 +4,7 @@ class Repository REF_MERGE_REQUEST = 'merge-requests'.freeze REF_KEEP_AROUND = 'keep-around'.freeze REF_ENVIRONMENTS = 'environments'.freeze + MAX_DIVERGING_COUNT = 1000 RESERVED_REFS_NAMES = %W[ heads @@ -102,6 +103,10 @@ class Repository "#<#{self.class.name}:#{@disk_path}>" end + def create_hooks + Gitlab::Git::Repository.create_hooks(path_to_repo, Gitlab.config.gitlab_shell.hooks_path) + end + def commit(ref = 'HEAD') return nil unless exists? return ref if ref.is_a?(::Commit) @@ -255,7 +260,7 @@ class Repository # This will still fail if the file is corrupted (e.g. 0 bytes) begin - write_ref(keep_around_ref_name(sha), sha) + raw_repository.write_ref(keep_around_ref_name(sha), sha, shell: false) rescue Rugged::ReferenceError => ex Rails.logger.error "Unable to create #{REF_KEEP_AROUND} reference for repository #{path}: #{ex}" rescue Rugged::OSError => ex @@ -269,20 +274,17 @@ class Repository ref_exists?(keep_around_ref_name(sha)) end - def write_ref(ref_path, sha) - rugged.references.create(ref_path, sha, force: true) - end - def diverging_commit_counts(branch) root_ref_hash = raw_repository.commit(root_ref).id cache.fetch(:"diverging_commit_counts_#{branch.name}") do # Rugged seems to throw a `ReferenceError` when given branch_names rather # than SHA-1 hashes - number_commits_behind = raw_repository - .count_commits_between(branch.dereferenced_target.sha, root_ref_hash) - - number_commits_ahead = raw_repository - .count_commits_between(root_ref_hash, branch.dereferenced_target.sha) + number_commits_behind, number_commits_ahead = + raw_repository.count_commits_between( + root_ref_hash, + branch.dereferenced_target.sha, + left_right: true, + max_count: MAX_DIVERGING_COUNT) { behind: number_commits_behind, ahead: number_commits_ahead } end @@ -781,34 +783,30 @@ class Repository end def create_dir(user, path, **options) - options[:user] = user options[:actions] = [{ action: :create_dir, file_path: path }] - multi_action(**options) + multi_action(user, **options) end def create_file(user, path, content, **options) - options[:user] = user options[:actions] = [{ action: :create, file_path: path, content: content }] - multi_action(**options) + multi_action(user, **options) end def update_file(user, path, content, **options) previous_path = options.delete(:previous_path) action = previous_path && previous_path != path ? :move : :update - options[:user] = user options[:actions] = [{ action: action, file_path: path, previous_path: previous_path, content: content }] - multi_action(**options) + multi_action(user, **options) end def delete_file(user, path, **options) - options[:user] = user options[:actions] = [{ action: :delete, file_path: path }] - multi_action(**options) + multi_action(user, **options) end def with_cache_hooks @@ -822,59 +820,14 @@ class Repository result.newrev end - def with_branch(user, *args) - with_cache_hooks do - Gitlab::Git::OperationService.new(user, raw_repository).with_branch(*args) do |start_commit| - yield start_commit - end - end - end - - # rubocop:disable Metrics/ParameterLists - def multi_action( - user:, branch_name:, message:, actions:, - author_email: nil, author_name: nil, - start_branch_name: nil, start_project: project) - - with_branch( - user, - branch_name, - start_branch_name: start_branch_name, - start_repository: start_project.repository.raw_repository) do |start_commit| - - index = Gitlab::Git::Index.new(raw_repository) + def multi_action(user, **options) + start_project = options.delete(:start_project) - if start_commit - index.read_tree(start_commit.rugged_commit.tree) - parents = [start_commit.sha] - else - parents = [] - end - - actions.each do |options| - index.public_send(options.delete(:action), options) # rubocop:disable GitlabSecurity/PublicSend - end - - options = { - tree: index.write_tree, - message: message, - parents: parents - } - options.merge!(get_committer_and_author(user, email: author_email, name: author_name)) - - create_commit(options) + if start_project + options[:start_repository] = start_project.repository.raw_repository end - end - # rubocop:enable Metrics/ParameterLists - - def get_committer_and_author(user, email: nil, name: nil) - committer = user_to_committer(user) - author = Gitlab::Git.committer_hash(email: email, name: name) || committer - { - author: author, - committer: committer - } + with_cache_hooks { raw.multi_action(user, **options) } end def can_be_merged?(source_sha, target_branch) @@ -1061,6 +1014,7 @@ class Repository else cache.fetch(key, &block) end + instance_variable_set(ivar, value) rescue Rugged::ReferenceError, Gitlab::Git::Repository::NoRepository # Even if the above `#exists?` check passes these errors might still @@ -1099,6 +1053,13 @@ class Repository @project.repository_storage_path end + def rebase(user, merge_request) + raw.rebase(user, merge_request.id, branch: merge_request.source_branch, + branch_sha: merge_request.source_branch_sha, + remote_repository: merge_request.target_project.repository.raw, + remote_branch: merge_request.target_branch) + end + private # TODO Generice finder, later split this on finders by Ref or Oid diff --git a/app/models/route.rb b/app/models/route.rb index 7ba3ec06041..412f5fb45a5 100644 --- a/app/models/route.rb +++ b/app/models/route.rb @@ -8,7 +8,7 @@ class Route < ActiveRecord::Base presence: true, uniqueness: { case_sensitive: false } - validate :ensure_permanent_paths + validate :ensure_permanent_paths, if: :path_changed? after_create :delete_conflicting_redirects after_update :delete_conflicting_redirects, if: :path_changed? diff --git a/app/models/service.rb b/app/models/service.rb index 3c4f1885dd0..7f260f7a96b 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -44,6 +44,7 @@ class Service < ActiveRecord::Base scope :pipeline_hooks, -> { where(pipeline_events: true, active: true) } scope :wiki_page_hooks, -> { where(wiki_page_events: true, active: true) } scope :external_issue_trackers, -> { issue_trackers.active.without_defaults } + scope :deployment, -> { where(category: 'deployment') } default_value_for :category, 'common' @@ -249,6 +250,7 @@ class Service < ActiveRecord::Base teamcity microsoft_teams ] + if Rails.env.development? service_names += %w[mock_ci mock_deployment mock_monitoring] end @@ -263,6 +265,18 @@ class Service < ActiveRecord::Base service end + def deprecated? + false + end + + def deprecation_message + nil + end + + def self.find_by_template + find_by(template: true) + end + private def cache_project_has_external_issue_tracker diff --git a/app/models/user.rb b/app/models/user.rb index b52f17cd6a8..4484ee9ff4c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -94,8 +94,8 @@ class User < ActiveRecord::Base has_one :user_synced_attributes_metadata, autosave: true # Groups - has_many :members, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent - has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, source: 'GroupMember' # rubocop:disable Cop/ActiveRecordDependent + has_many :members + has_many :group_members, -> { where(requested_at: nil) }, source: 'GroupMember' has_many :groups, through: :group_members has_many :owned_groups, -> { where members: { access_level: Gitlab::Access::OWNER } }, through: :group_members, source: :group has_many :masters_groups, -> { where members: { access_level: Gitlab::Access::MASTER } }, through: :group_members, source: :group @@ -103,7 +103,7 @@ class User < ActiveRecord::Base # Projects has_many :groups_projects, through: :groups, source: :projects has_many :personal_projects, through: :namespace, source: :projects - has_many :project_members, -> { where(requested_at: nil) }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent + has_many :project_members, -> { where(requested_at: nil) } has_many :projects, through: :project_members has_many :created_projects, foreign_key: :creator_id, class_name: 'Project' has_many :users_star_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent @@ -794,10 +794,7 @@ class User < ActiveRecord::Base # `User.select(:id)` raises # `ActiveModel::MissingAttributeError: missing attribute: projects_limit` # without this safeguard! - return unless has_attribute?(:projects_limit) - - connection_default_value_defined = new_record? && !projects_limit_changed? - return unless projects_limit.nil? || connection_default_value_defined + return unless has_attribute?(:projects_limit) && projects_limit.nil? self.projects_limit = current_application_settings.default_projects_limit end |