diff options
author | Kamil Trzcinski <ayufan@ayufan.eu> | 2017-04-06 22:00:00 +0200 |
---|---|---|
committer | Kamil Trzcinski <ayufan@ayufan.eu> | 2017-04-06 22:05:22 +0200 |
commit | 37a7b099d6eafc87209368a9fc7f608282b99e08 (patch) | |
tree | a2712e439cec8547d84bed2d57d339cb1cd5c502 /app/models | |
parent | 57c353fca7121a120142161b253004f33d815766 (diff) | |
parent | 73cb71e41c0ade92b9673a5d74c7dd78679fae91 (diff) | |
download | gitlab-ce-optimise-pipelines.tar.gz |
Merge remote-tracking branch 'origin/master' into optimise-pipelinesoptimise-pipelines
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/award_emoji.rb | 3 | ||||
-rw-r--r-- | app/models/blob.rb | 18 | ||||
-rw-r--r-- | app/models/ci/build.rb | 162 | ||||
-rw-r--r-- | app/models/ci/trigger.rb | 1 | ||||
-rw-r--r-- | app/models/ci/trigger_schedule.rb | 30 | ||||
-rw-r--r-- | app/models/concerns/ghost_user.rb | 7 | ||||
-rw-r--r-- | app/models/concerns/routable.rb | 68 | ||||
-rw-r--r-- | app/models/container_repository.rb | 77 | ||||
-rw-r--r-- | app/models/group.rb | 11 | ||||
-rw-r--r-- | app/models/issue.rb | 15 | ||||
-rw-r--r-- | app/models/members/group_member.rb | 5 | ||||
-rw-r--r-- | app/models/namespace.rb | 10 | ||||
-rw-r--r-- | app/models/project.rb | 58 | ||||
-rw-r--r-- | app/models/project_services/mock_deployment_service.rb | 18 | ||||
-rw-r--r-- | app/models/project_services/mock_monitoring_service.rb | 17 | ||||
-rw-r--r-- | app/models/repository.rb | 27 | ||||
-rw-r--r-- | app/models/service.rb | 4 | ||||
-rw-r--r-- | app/models/user.rb | 20 |
18 files changed, 359 insertions, 192 deletions
diff --git a/app/models/award_emoji.rb b/app/models/award_emoji.rb index 6937ad3bdd9..6ada6fae4eb 100644 --- a/app/models/award_emoji.rb +++ b/app/models/award_emoji.rb @@ -3,13 +3,14 @@ class AwardEmoji < ActiveRecord::Base UPVOTE_NAME = "thumbsup".freeze include Participable + include GhostUser belongs_to :awardable, polymorphic: true belongs_to :user validates :awardable, :user, presence: true validates :name, presence: true, inclusion: { in: Gitlab::Emoji.emojis_names } - validates :name, uniqueness: { scope: [:user, :awardable_type, :awardable_id] } + validates :name, uniqueness: { scope: [:user, :awardable_type, :awardable_id] }, unless: :ghost_user? participant :user diff --git a/app/models/blob.rb b/app/models/blob.rb index 95d2111a992..801d3442803 100644 --- a/app/models/blob.rb +++ b/app/models/blob.rb @@ -46,10 +46,22 @@ class Blob < SimpleDelegator text? && language && language.name == 'SVG' end + def pdf? + name && File.extname(name) == '.pdf' + end + def ipython_notebook? text? && language&.name == 'Jupyter Notebook' end + def sketch? + binary? && extname.downcase.delete('.') == 'sketch' + end + + def stl? + extname.downcase.delete('.') == 'stl' + end + def size_within_svg_limits? size <= MAXIMUM_SVG_SIZE end @@ -67,8 +79,14 @@ class Blob < SimpleDelegator end elsif image? || svg? 'image' + elsif pdf? + 'pdf' elsif ipython_notebook? 'notebook' + elsif sketch? + 'sketch' + elsif stl? + 'stl' elsif text? 'text' else diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 9ef55fa6e18..b426c27afbb 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -165,19 +165,6 @@ module Ci latest_builds.where('stage_idx < ?', stage_idx) end - def trace_html(**args) - trace_with_state(**args)[:html] || '' - end - - def trace_with_state(state: nil, last_lines: nil) - trace_ansi = trace(last_lines: last_lines) - if trace_ansi.present? - Ci::Ansi2html.convert(trace_ansi, state) - else - {} - end - end - def timeout project.build_timeout end @@ -238,136 +225,35 @@ module Ci end def update_coverage - coverage = extract_coverage(trace, coverage_regex) + coverage = trace.extract_coverage(coverage_regex) update_attributes(coverage: coverage) if coverage.present? end - def extract_coverage(text, regex) - return unless regex - - matches = text.scan(Regexp.new(regex)).last - matches = matches.last if matches.is_a?(Array) - coverage = matches.gsub(/\d+(\.\d+)?/).first - - if coverage.present? - coverage.to_f - end - rescue - # if bad regex or something goes wrong we dont want to interrupt transition - # so we just silentrly ignore error for now - end - - def has_trace_file? - File.exist?(path_to_trace) || has_old_trace_file? + def trace + Gitlab::Ci::Trace.new(self) end def has_trace? - raw_trace.present? - end - - def raw_trace(last_lines: nil) - if File.exist?(trace_file_path) - Gitlab::Ci::TraceReader.new(trace_file_path). - read(last_lines: last_lines) - else - # backward compatibility - read_attribute :trace - end - end - - ## - # Deprecated - # - # This is a hotfix for CI build data integrity, see #4246 - def has_old_trace_file? - project.ci_id && File.exist?(old_path_to_trace) - end - - def trace(last_lines: nil) - hide_secrets(raw_trace(last_lines: last_lines)) - end - - def trace_length - if raw_trace - raw_trace.bytesize - else - 0 - end + trace.exist? end - def trace=(trace) - recreate_trace_dir - trace = hide_secrets(trace) - File.write(path_to_trace, trace) + def trace=(data) + raise NotImplementedError end - def recreate_trace_dir - unless Dir.exist?(dir_to_trace) - FileUtils.mkdir_p(dir_to_trace) - end + def old_trace + read_attribute(:trace) end - private :recreate_trace_dir - - def append_trace(trace_part, offset) - recreate_trace_dir - touch if needs_touch? - - trace_part = hide_secrets(trace_part) - File.truncate(path_to_trace, offset) if File.exist?(path_to_trace) - File.open(path_to_trace, 'ab') do |f| - f.write(trace_part) - end + def erase_old_trace! + write_attribute(:trace, nil) + save end def needs_touch? Time.now - updated_at > 15.minutes.to_i end - def trace_file_path - if has_old_trace_file? - old_path_to_trace - else - path_to_trace - end - end - - def dir_to_trace - File.join( - Settings.gitlab_ci.builds_path, - created_at.utc.strftime("%Y_%m"), - project.id.to_s - ) - end - - def path_to_trace - "#{dir_to_trace}/#{id}.log" - end - - ## - # Deprecated - # - # This is a hotfix for CI build data integrity, see #4246 - # Should be removed in 8.4, after CI files migration has been done. - # - def old_dir_to_trace - File.join( - Settings.gitlab_ci.builds_path, - created_at.utc.strftime("%Y_%m"), - project.ci_id.to_s - ) - end - - ## - # Deprecated - # - # This is a hotfix for CI build data integrity, see #4246 - # Should be removed in 8.4, after CI files migration has been done. - # - def old_path_to_trace - "#{old_dir_to_trace}/#{id}.log" - end - ## # Deprecated # @@ -534,6 +420,8 @@ module Ci end def dependencies + return [] if empty_dependencies? + depended_jobs = depends_on_builds return depended_jobs unless options[:dependencies].present? @@ -543,6 +431,19 @@ module Ci end end + def empty_dependencies? + options[:dependencies]&.empty? + end + + def hide_secrets(trace) + return unless trace + + trace = trace.dup + Ci::MaskSecret.mask!(trace, project.runners_token) if project + Ci::MaskSecret.mask!(trace, token) + trace + end + private def update_artifacts_size @@ -554,7 +455,7 @@ module Ci end def erase_trace! - self.trace = nil + trace.erase! end def update_erased!(user = nil) @@ -616,15 +517,6 @@ module Ci pipeline.config_processor.build_attributes(name) end - def hide_secrets(trace) - return unless trace - - trace = trace.dup - Ci::MaskSecret.mask!(trace, project.runners_token) if project - Ci::MaskSecret.mask!(trace, token) - trace - end - def update_project_statistics return unless project diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb index cba1d81a861..0a89f3e0640 100644 --- a/app/models/ci/trigger.rb +++ b/app/models/ci/trigger.rb @@ -8,6 +8,7 @@ module Ci belongs_to :owner, class_name: "User" has_many :trigger_requests, dependent: :destroy + has_one :trigger_schedule, dependent: :destroy validates :token, presence: true, uniqueness: true diff --git a/app/models/ci/trigger_schedule.rb b/app/models/ci/trigger_schedule.rb new file mode 100644 index 00000000000..10ea381ee31 --- /dev/null +++ b/app/models/ci/trigger_schedule.rb @@ -0,0 +1,30 @@ +module Ci + class TriggerSchedule < ActiveRecord::Base + extend Ci::Model + include Importable + + acts_as_paranoid + + belongs_to :project + belongs_to :trigger + + delegate :ref, to: :trigger + + validates :trigger, presence: { unless: :importing? } + validates :cron, cron: true, presence: { unless: :importing? } + validates :cron_timezone, cron_timezone: true, presence: { unless: :importing? } + validates :ref, presence: { unless: :importing? } + + before_save :set_next_run_at + + def set_next_run_at + self.next_run_at = Gitlab::Ci::CronParser.new(cron, cron_timezone).next_time_from(Time.now) + end + + def schedule_next_run! + save! # with set_next_run_at + rescue ActiveRecord::RecordInvalid + update_attribute(:next_run_at, nil) # update without validation + end + end +end diff --git a/app/models/concerns/ghost_user.rb b/app/models/concerns/ghost_user.rb new file mode 100644 index 00000000000..da696127a80 --- /dev/null +++ b/app/models/concerns/ghost_user.rb @@ -0,0 +1,7 @@ +module GhostUser + extend ActiveSupport::Concern + + def ghost_user? + user && user.ghost? + end +end diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb index 529fb5ce988..aca99feee53 100644 --- a/app/models/concerns/routable.rb +++ b/app/models/concerns/routable.rb @@ -83,6 +83,74 @@ module Routable AND members.source_type = r2.source_type"). where('members.user_id = ?', user_id) end + + # Builds a relation to find multiple objects that are nested under user + # membership. Includes the parent, as opposed to `#member_descendants` + # which only includes the descendants. + # + # Usage: + # + # Klass.member_self_and_descendants(1) + # + # Returns an ActiveRecord::Relation. + def member_self_and_descendants(user_id) + joins(:route). + joins("INNER JOIN routes r2 ON routes.path LIKE CONCAT(r2.path, '/%') + OR routes.path = r2.path + INNER JOIN members ON members.source_id = r2.source_id + AND members.source_type = r2.source_type"). + where('members.user_id = ?', user_id) + end + + # Returns all objects in a hierarchy, where any node in the hierarchy is + # under the user membership. + # + # Usage: + # + # Klass.member_hierarchy(1) + # + # Examples: + # + # Given the following group tree... + # + # _______group_1_______ + # | | + # | | + # nested_group_1 nested_group_2 + # | | + # | | + # nested_group_1_1 nested_group_2_1 + # + # + # ... the following results are returned: + # + # * the user is a member of group 1 + # => 'group_1', + # 'nested_group_1', nested_group_1_1', + # 'nested_group_2', 'nested_group_2_1' + # + # * the user is a member of nested_group_2 + # => 'group1', + # 'nested_group_2', 'nested_group_2_1' + # + # * the user is a member of nested_group_2_1 + # => 'group1', + # 'nested_group_2', 'nested_group_2_1' + # + # Returns an ActiveRecord::Relation. + def member_hierarchy(user_id) + paths = member_self_and_descendants(user_id).pluck('routes.path') + + return none if paths.empty? + + wheres = paths.map do |path| + "#{connection.quote(path)} = routes.path + OR + #{connection.quote(path)} LIKE CONCAT(routes.path, '/%')" + end + + joins(:route).where(wheres.join(' OR ')) + end end def full_name diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb new file mode 100644 index 00000000000..9682df3a586 --- /dev/null +++ b/app/models/container_repository.rb @@ -0,0 +1,77 @@ +class ContainerRepository < ActiveRecord::Base + belongs_to :project + + validates :name, length: { minimum: 0, allow_nil: false } + validates :name, uniqueness: { scope: :project_id } + + delegate :client, to: :registry + + before_destroy :delete_tags! + + def registry + @registry ||= begin + token = Auth::ContainerRegistryAuthenticationService.full_access_token(path) + + url = Gitlab.config.registry.api_url + host_port = Gitlab.config.registry.host_port + + ContainerRegistry::Registry.new(url, token: token, path: host_port) + end + end + + def path + @path ||= [project.full_path, name].select(&:present?).join('/') + end + + def tag(tag) + ContainerRegistry::Tag.new(self, tag) + end + + def manifest + @manifest ||= client.repository_tags(path) + end + + def tags + return @tags if defined?(@tags) + return [] unless manifest && manifest['tags'] + + @tags = manifest['tags'].map do |tag| + ContainerRegistry::Tag.new(self, tag) + end + end + + def blob(config) + ContainerRegistry::Blob.new(self, config) + end + + def has_tags? + tags.any? + end + + def root_repository? + name.empty? + end + + def delete_tags! + return unless has_tags? + + digests = tags.map { |tag| tag.digest }.to_set + + digests.all? do |digest| + client.delete_repository_tag(self.path, digest) + end + end + + def self.build_from_path(path) + self.new(project: path.repository_project, + name: path.repository_name) + end + + def self.create_from_path!(path) + build_from_path(path).tap(&:save!) + end + + def self.build_root_repository(project) + self.new(project: project, name: '') + end +end diff --git a/app/models/group.rb b/app/models/group.rb index 60274386103..106084175ff 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -27,11 +27,14 @@ class Group < Namespace validates :avatar, file_size: { maximum: 200.kilobytes.to_i } + validates :two_factor_grace_period, presence: true, numericality: { greater_than_or_equal_to: 0 } + mount_uploader :avatar, AvatarUploader has_many :uploads, as: :model, dependent: :destroy after_create :post_create_hook after_destroy :post_destroy_hook + after_save :update_two_factor_requirement class << self # Searches for groups matching the given query. @@ -223,4 +226,12 @@ class Group < Namespace type: public? ? 'O' : 'I' # Open vs Invite-only } end + + protected + + def update_two_factor_requirement + return unless require_two_factor_authentication_changed? || two_factor_grace_period_changed? + + users.find_each(&:update_two_factor_requirement) + end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 10a5d9d2a24..f9704b0d754 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -40,6 +40,8 @@ class Issue < ActiveRecord::Base scope :include_associations, -> { includes(:assignee, :labels, project: :namespace) } + after_save :expire_etag_cache + attr_spammable :title, spam_title: true attr_spammable :description, spam_description: true @@ -59,10 +61,6 @@ class Issue < ActiveRecord::Base before_transition any => :closed do |issue| issue.closed_at = Time.zone.now end - - before_transition closed: any do |issue| - issue.closed_at = nil - end end def hook_attrs @@ -256,4 +254,13 @@ class Issue < ActiveRecord::Base def publicly_visible? project.public? && !confidential? end + + def expire_etag_cache + key = Gitlab::Routing.url_helpers.rendered_title_namespace_project_issue_path( + project.namespace, + project, + self + ) + Gitlab::EtagCaching::Store.new.touch(key) + end end diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb index 446f9f8f8a7..483425cd30f 100644 --- a/app/models/members/group_member.rb +++ b/app/models/members/group_member.rb @@ -3,11 +3,16 @@ class GroupMember < Member belongs_to :group, foreign_key: 'source_id' + delegate :update_two_factor_requirement, to: :user + # Make sure group member points only to group as it source default_value_for :source_type, SOURCE_TYPE validates :source_type, format: { with: /\ANamespace\z/ } default_scope { where(source_type: SOURCE_TYPE) } + after_create :update_two_factor_requirement, unless: :invite? + after_destroy :update_two_factor_requirement, unless: :invite? + def self.access_level_roles Gitlab::Access.options_with_owner end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 1d4b1f7d590..9bfa731785f 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -150,7 +150,7 @@ class Namespace < ActiveRecord::Base end def any_project_has_container_registry_tags? - projects.any?(&:has_container_registry_tags?) + all_projects.any?(&:has_container_registry_tags?) end def send_update_instructions @@ -214,6 +214,12 @@ class Namespace < ActiveRecord::Base @old_repository_storage_paths ||= repository_storage_paths end + # Includes projects from this namespace and projects from all subgroups + # that belongs to this namespace + def all_projects + Project.inside_path(full_path) + end + private def repository_storage_paths @@ -221,7 +227,7 @@ class Namespace < ActiveRecord::Base # pending delete. Unscoping also get rids of the default order, which causes # problems with SELECT DISTINCT. Project.unscoped do - projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path) + all_projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path) end end diff --git a/app/models/project.rb b/app/models/project.rb index 112209fef30..571f9755e20 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -114,6 +114,8 @@ class Project < ActiveRecord::Base has_one :kubernetes_service, dependent: :destroy, inverse_of: :project has_one :prometheus_service, dependent: :destroy, inverse_of: :project has_one :mock_ci_service, dependent: :destroy + has_one :mock_deployment_service, dependent: :destroy + has_one :mock_monitoring_service, dependent: :destroy has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" has_one :forked_from_project, through: :forked_project_link @@ -157,6 +159,7 @@ class Project < ActiveRecord::Base has_one :import_data, dependent: :destroy, class_name: "ProjectImportData" has_one :project_feature, dependent: :destroy has_one :statistics, class_name: 'ProjectStatistics', dependent: :delete + has_many :container_repositories, dependent: :destroy has_many :commit_statuses, dependent: :destroy has_many :pipelines, dependent: :destroy, class_name: 'Ci::Pipeline' @@ -349,10 +352,15 @@ class Project < ActiveRecord::Base end def sort(method) - if method == 'storage_size_desc' + case method.to_s + when 'storage_size_desc' # storage_size is a joined column so we need to # pass a string to avoid AR adding the table name reorder('project_statistics.storage_size DESC, projects.id DESC') + when 'latest_activity_desc' + reorder(last_activity_at: :desc) + when 'latest_activity_asc' + reorder(last_activity_at: :asc) else order_by(method) end @@ -401,32 +409,15 @@ class Project < ActiveRecord::Base @repository ||= Repository.new(path_with_namespace, self) end - def container_registry_path_with_namespace - path_with_namespace.downcase - end - - def container_registry_repository - return unless Gitlab.config.registry.enabled - - @container_registry_repository ||= begin - token = Auth::ContainerRegistryAuthenticationService.full_access_token(container_registry_path_with_namespace) - url = Gitlab.config.registry.api_url - host_port = Gitlab.config.registry.host_port - registry = ContainerRegistry::Registry.new(url, token: token, path: host_port) - registry.repository(container_registry_path_with_namespace) - end - end - - def container_registry_repository_url + def container_registry_url if Gitlab.config.registry.enabled - "#{Gitlab.config.registry.host_port}/#{container_registry_path_with_namespace}" + "#{Gitlab.config.registry.host_port}/#{path_with_namespace.downcase}" end end def has_container_registry_tags? - return unless container_registry_repository - - container_registry_repository.tags.any? + container_repositories.to_a.any?(&:has_tags?) || + has_root_container_repository_tags? end def commit(ref = 'HEAD') @@ -917,10 +908,10 @@ class Project < ActiveRecord::Base expire_caches_before_rename(old_path_with_namespace) if has_container_registry_tags? - Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present" + Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present!" - # we currently doesn't support renaming repository if it contains tags in container registry - raise StandardError.new('Project cannot be renamed, because tags are present in its container registry') + # we currently doesn't support renaming repository if it contains images in container registry + raise StandardError.new('Project cannot be renamed, because images are present in its container registry') end if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace) @@ -1110,10 +1101,6 @@ class Project < ActiveRecord::Base self.runners_token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.runners_token) end - def build_coverage_enabled? - build_coverage_regex.present? - end - def build_timeout_in_minutes build_timeout / 60 end @@ -1267,7 +1254,7 @@ class Project < ActiveRecord::Base ] if container_registry_enabled? - variables << { key: 'CI_REGISTRY_IMAGE', value: container_registry_repository_url, public: true } + variables << { key: 'CI_REGISTRY_IMAGE', value: container_registry_url, public: true } end variables @@ -1400,4 +1387,15 @@ class Project < ActiveRecord::Base Project.unscoped.where(pending_delete: true).find_by_full_path(path_with_namespace) end + + ## + # This method is here because of support for legacy container repository + # which has exactly the same path like project does, but which might not be + # persisted in `container_repositories` table. + # + def has_root_container_repository_tags? + return false unless Gitlab.config.registry.enabled + + ContainerRepository.build_root_repository(self).has_tags? + end end diff --git a/app/models/project_services/mock_deployment_service.rb b/app/models/project_services/mock_deployment_service.rb new file mode 100644 index 00000000000..59a3811ce5d --- /dev/null +++ b/app/models/project_services/mock_deployment_service.rb @@ -0,0 +1,18 @@ +class MockDeploymentService < DeploymentService + def title + 'Mock deployment' + end + + def description + 'Mock deployment service' + end + + def self.to_param + 'mock_deployment' + end + + # No terminals support + def terminals(environment) + [] + end +end diff --git a/app/models/project_services/mock_monitoring_service.rb b/app/models/project_services/mock_monitoring_service.rb new file mode 100644 index 00000000000..dd04e04e198 --- /dev/null +++ b/app/models/project_services/mock_monitoring_service.rb @@ -0,0 +1,17 @@ +class MockMonitoringService < MonitoringService + def title + 'Mock monitoring' + end + + def description + 'Mock monitoring service' + end + + def self.to_param + 'mock_monitoring' + end + + def metrics(environment) + JSON.parse(File.read(Rails.root + 'spec/fixtures/metrics.json')) + end +end diff --git a/app/models/repository.rb b/app/models/repository.rb index 6b2383b73eb..1293cb1d486 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -6,6 +6,8 @@ class Repository attr_accessor :path_with_namespace, :project + delegate :ref_name_for_sha, to: :raw_repository + CommitError = Class.new(StandardError) CreateTreeError = Class.new(StandardError) @@ -59,7 +61,7 @@ class Repository def raw_repository return nil unless path_with_namespace - @raw_repository ||= Gitlab::Git::Repository.new(path_to_repo) + @raw_repository ||= initialize_raw_repository end # Return absolute path to repository @@ -146,12 +148,7 @@ class Repository # may cause the branch to "disappear" erroneously or have the wrong SHA. # # See: https://github.com/libgit2/libgit2/issues/1534 and https://gitlab.com/gitlab-org/gitlab-ce/issues/15392 - raw_repo = - if fresh_repo - Gitlab::Git::Repository.new(path_to_repo) - else - raw_repository - end + raw_repo = fresh_repo ? initialize_raw_repository : raw_repository raw_repo.find_branch(name) end @@ -505,9 +502,7 @@ class Repository end end - def branch_names - branches.map(&:name) - end + delegate :branch_names, to: :raw_repository cache_method :branch_names, fallback: [] delegate :tag_names, to: :raw_repository @@ -707,14 +702,6 @@ class Repository end end - def ref_name_for_sha(ref_path, sha) - args = %W(#{Gitlab.config.git.bin_path} for-each-ref --count=1 #{ref_path} --contains #{sha}) - - # Not found -> ["", 0] - # Found -> ["b8d95eb4969eefacb0a58f6a28f6803f8070e7b9 commit\trefs/environments/production/77\n", 0] - Gitlab::Popen.popen(args, path_to_repo).first.split.last - end - def refs_contains_sha(ref_type, sha) args = %W(#{Gitlab.config.git.bin_path} #{ref_type} --contains #{sha}) names = Gitlab::Popen.popen(args, path_to_repo).first @@ -1168,4 +1155,8 @@ class Repository def repository_storage_path @project.repository_storage_path end + + def initialize_raw_repository + Gitlab::Git::Repository.new(project.repository_storage, path_with_namespace + '.git') + end end diff --git a/app/models/service.rb b/app/models/service.rb index 54550177744..5a0ec58d193 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -238,7 +238,9 @@ class Service < ActiveRecord::Base slack teamcity ] - service_names << 'mock_ci' if Rails.env.development? + if Rails.env.development? + service_names += %w[mock_ci mock_deployment mock_monitoring] + end service_names.sort_by(&:downcase) end diff --git a/app/models/user.rb b/app/models/user.rb index 95a766f2ede..87eeee204f8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -89,7 +89,8 @@ class User < ActiveRecord::Base has_many :subscriptions, dependent: :destroy has_many :recent_events, -> { order "id DESC" }, foreign_key: :author_id, class_name: "Event" has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy - has_one :abuse_report, dependent: :destroy + has_one :abuse_report, dependent: :destroy, foreign_key: :user_id + has_many :reported_abuse_reports, dependent: :destroy, foreign_key: :reporter_id, class_name: "AbuseReport" has_many :spam_logs, dependent: :destroy has_many :builds, dependent: :nullify, class_name: 'Ci::Build' has_many :pipelines, dependent: :nullify, class_name: 'Ci::Pipeline' @@ -484,6 +485,14 @@ class User < ActiveRecord::Base Group.member_descendants(id) end + def all_expanded_groups + Group.member_hierarchy(id) + end + + def expanded_groups_requiring_two_factor_authentication + all_expanded_groups.where(require_two_factor_authentication: true) + end + def nested_groups_projects Project.joins(:namespace).where('namespaces.parent_id IS NOT NULL'). member_descendants(id) @@ -955,6 +964,15 @@ class User < ActiveRecord::Base self.admin = (new_level == 'admin') end + def update_two_factor_requirement + periods = expanded_groups_requiring_two_factor_authentication.pluck(:two_factor_grace_period) + + self.require_two_factor_authentication_from_group = periods.any? + self.two_factor_grace_period = periods.min || User.column_defaults['two_factor_grace_period'] + + save + end + protected # override, from Devise::Validatable |