summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
authorShinya Maeda <shinya@gitlab.com>2018-05-28 20:01:56 +0900
committerShinya Maeda <shinya@gitlab.com>2018-05-28 20:01:56 +0900
commit1d20679e9c8b1ba16bebaf982255946e7207b4d4 (patch)
tree128685af66ca56c751b505a8314ca79dd3b54b34 /app/models
parent8e92e25b62ca108de775362e6d2981e54535f094 (diff)
parent014f5f6a69f63ee42bd94454108268f189b62b18 (diff)
downloadgitlab-ce-1d20679e9c8b1ba16bebaf982255946e7207b4d4.tar.gz
Merge branch 'master' into per-project-pipeline-iid
Diffstat (limited to 'app/models')
-rw-r--r--app/models/appearance.rb15
-rw-r--r--app/models/application_setting.rb36
-rw-r--r--app/models/ci/build.rb2
-rw-r--r--app/models/concerns/cacheable_attributes.rb54
-rw-r--r--app/models/concerns/resolvable_note.rb2
-rw-r--r--app/models/merge_request.rb29
-rw-r--r--app/models/project.rb11
-rw-r--r--app/models/project_services/drone_ci_service.rb2
-rw-r--r--app/models/project_services/gemnasium_service.rb13
-rw-r--r--app/models/repository.rb20
-rw-r--r--app/models/service.rb1
-rw-r--r--app/models/user.rb29
12 files changed, 144 insertions, 70 deletions
diff --git a/app/models/appearance.rb b/app/models/appearance.rb
index f8713138a93..67cc84a9140 100644
--- a/app/models/appearance.rb
+++ b/app/models/appearance.rb
@@ -1,6 +1,6 @@
class Appearance < ActiveRecord::Base
+ include CacheableAttributes
include CacheMarkdownField
- include AfterCommitQueue
include ObjectStorage::BackgroundMove
include WithUploads
@@ -15,16 +15,9 @@ class Appearance < ActiveRecord::Base
mount_uploader :logo, AttachmentUploader
mount_uploader :header_logo, AttachmentUploader
- CACHE_KEY = "current_appearance:#{Gitlab::VERSION}".freeze
-
- after_commit :flush_redis_cache
-
- def self.current
- Rails.cache.fetch(CACHE_KEY) { first }
- end
-
- def flush_redis_cache
- Rails.cache.delete(CACHE_KEY)
+ # Overrides CacheableAttributes.current_without_cache
+ def self.current_without_cache
+ first
end
def single_appearance_row
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 451e512aef7..e8ccb320fae 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -1,11 +1,11 @@
class ApplicationSetting < ActiveRecord::Base
+ include CacheableAttributes
include CacheMarkdownField
include TokenAuthenticatable
add_authentication_token_field :runners_registration_token
add_authentication_token_field :health_check_access_token
- CACHE_KEY = 'application_setting.last'.freeze
DOMAIN_LIST_SEPARATOR = %r{\s*[,;]\s* # comma or semicolon, optionally surrounded by whitespace
| # or
\s # any whitespace character
@@ -229,40 +229,6 @@ class ApplicationSetting < ActiveRecord::Base
after_commit do
reset_memoized_terms
- Rails.cache.write(CACHE_KEY, self)
- end
-
- def self.current
- ensure_cache_setup
-
- Rails.cache.fetch(CACHE_KEY) do
- ApplicationSetting.last.tap do |settings|
- # do not cache nils
- raise 'missing settings' unless settings
- end
- end
- rescue
- # Fall back to an uncached value if there are any problems (e.g. redis down)
- ApplicationSetting.last
- end
-
- def self.expire
- Rails.cache.delete(CACHE_KEY)
- rescue
- # Gracefully handle when Redis is not available. For example,
- # omnibus may fail here during gitlab:assets:compile.
- end
-
- def self.cached
- value = Rails.cache.read(CACHE_KEY)
- ensure_cache_setup if value.present?
- value
- end
-
- def self.ensure_cache_setup
- # This is a workaround for a Rails bug that causes attribute methods not
- # to be loaded when read from cache: https://github.com/rails/rails/issues/27348
- ApplicationSetting.define_attribute_methods
end
def self.defaults
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 495430931aa..75fd55a8f7b 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -618,7 +618,7 @@ module Ci
variables.append(key: 'GITLAB_FEATURES', value: project.licensed_features.join(','))
variables.append(key: 'CI_SERVER_NAME', value: 'GitLab')
variables.append(key: 'CI_SERVER_VERSION', value: Gitlab::VERSION)
- variables.append(key: 'CI_SERVER_REVISION', value: Gitlab::REVISION)
+ variables.append(key: 'CI_SERVER_REVISION', value: Gitlab.revision)
variables.append(key: 'CI_JOB_NAME', value: name)
variables.append(key: 'CI_JOB_STAGE', value: stage)
variables.append(key: 'CI_COMMIT_SHA', value: sha)
diff --git a/app/models/concerns/cacheable_attributes.rb b/app/models/concerns/cacheable_attributes.rb
new file mode 100644
index 00000000000..b32459fdabf
--- /dev/null
+++ b/app/models/concerns/cacheable_attributes.rb
@@ -0,0 +1,54 @@
+module CacheableAttributes
+ extend ActiveSupport::Concern
+
+ included do
+ after_commit { self.class.expire }
+ end
+
+ class_methods do
+ # Can be overriden
+ def current_without_cache
+ last
+ end
+
+ def cache_key
+ "#{name}:#{Gitlab::VERSION}:#{Gitlab.migrations_hash}:json".freeze
+ end
+
+ def defaults
+ {}
+ end
+
+ def build_from_defaults(attributes = {})
+ new(defaults.merge(attributes))
+ end
+
+ def cached
+ json_attributes = Rails.cache.read(cache_key)
+ return nil unless json_attributes.present?
+
+ build_from_defaults(JSON.parse(json_attributes))
+ end
+
+ def current
+ cached_record = cached
+ return cached_record if cached_record.present?
+
+ current_without_cache.tap { |current_record| current_record&.cache! }
+ rescue
+ # Fall back to an uncached value if there are any problems (e.g. Redis down)
+ current_without_cache
+ end
+
+ def expire
+ Rails.cache.delete(cache_key)
+ rescue
+ # Gracefully handle when Redis is not available. For example,
+ # omnibus may fail here during gitlab:assets:compile.
+ end
+ end
+
+ def cache!
+ Rails.cache.write(self.class.cache_key, attributes.to_json)
+ end
+end
diff --git a/app/models/concerns/resolvable_note.rb b/app/models/concerns/resolvable_note.rb
index 668c5a079e3..4a0f8b92b3a 100644
--- a/app/models/concerns/resolvable_note.rb
+++ b/app/models/concerns/resolvable_note.rb
@@ -32,7 +32,7 @@ module ResolvableNote
# Keep this method in sync with the `potentially_resolvable` scope
def potentially_resolvable?
- RESOLVABLE_TYPES.include?(self.class.name) && noteable.supports_resolvable_notes?
+ RESOLVABLE_TYPES.include?(self.class.name) && noteable&.supports_resolvable_notes?
end
# Keep this method in sync with the `resolvable` scope
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index f42d432cc66..a00b8d4e2c1 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -105,24 +105,35 @@ class MergeRequest < ActiveRecord::Base
state_machine :merge_status, initial: :unchecked do
event :mark_as_unchecked do
- transition [:can_be_merged, :cannot_be_merged] => :unchecked
+ transition [:can_be_merged, :unchecked] => :unchecked
+ transition [:cannot_be_merged, :cannot_be_merged_recheck] => :cannot_be_merged_recheck
end
event :mark_as_mergeable do
- transition [:unchecked, :cannot_be_merged] => :can_be_merged
+ transition [:unchecked, :cannot_be_merged_recheck] => :can_be_merged
end
event :mark_as_unmergeable do
- transition [:unchecked, :can_be_merged] => :cannot_be_merged
+ transition [:unchecked, :cannot_be_merged_recheck] => :cannot_be_merged
end
state :unchecked
+ state :cannot_be_merged_recheck
state :can_be_merged
state :cannot_be_merged
around_transition do |merge_request, transition, block|
Gitlab::Timeless.timeless(merge_request, &block)
end
+
+ after_transition unchecked: :cannot_be_merged do |merge_request, transition|
+ NotificationService.new.merge_request_unmergeable(merge_request)
+ TodoService.new.merge_request_became_unmergeable(merge_request)
+ end
+
+ def check_state?(merge_status)
+ [:unchecked, :cannot_be_merged_recheck].include?(merge_status.to_sym)
+ end
end
validates :source_project, presence: true, unless: [:allow_broken, :importing?, :closed_without_fork?]
@@ -328,6 +339,16 @@ class MergeRequest < ActiveRecord::Base
update_column(:merge_jid, jid)
end
+ def merge_participants
+ participants = [author]
+
+ if merge_when_pipeline_succeeds? && !participants.include?(merge_user)
+ participants << merge_user
+ end
+
+ participants
+ end
+
def first_commit
merge_request_diff ? merge_request_diff.first_commit : compare_commits.first
end
@@ -603,7 +624,7 @@ class MergeRequest < ActiveRecord::Base
end
def check_if_can_be_merged
- return unless unchecked? && Gitlab::Database.read_write?
+ return unless self.class.state_machines[:merge_status].check_state?(merge_status) && Gitlab::Database.read_write?
can_be_merged =
!broken? && project.repository.can_be_merged?(diff_head_sha, target_branch)
diff --git a/app/models/project.rb b/app/models/project.rb
index 35c873830a7..0fe9f8880b4 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -894,6 +894,13 @@ class Project < ActiveRecord::Base
Gitlab::Routing.url_helpers.project_url(self)
end
+ def readme_url
+ readme = repository.readme
+ if readme
+ Gitlab::Routing.url_helpers.project_blob_url(self, File.join(default_branch, readme.path))
+ end
+ end
+
def new_issuable_address(author, address_type)
return unless Gitlab::IncomingEmail.supports_issue_creation? && author
@@ -1424,8 +1431,8 @@ class Project < ActiveRecord::Base
self.runners_token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.runners_token)
end
- def open_issues_count
- Projects::OpenIssuesCountService.new(self).count
+ def open_issues_count(current_user = nil)
+ Projects::OpenIssuesCountService.new(self, current_user).count
end
def open_merge_requests_count
diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb
index 71b10fc6bc1..a4bf427ac0b 100644
--- a/app/models/project_services/drone_ci_service.rb
+++ b/app/models/project_services/drone_ci_service.rb
@@ -115,6 +115,6 @@ class DroneCiService < CiService
def merge_request_valid?(data)
data[:object_attributes][:state] == 'opened' &&
- data[:object_attributes][:merge_status] == 'unchecked'
+ MergeRequest.state_machines[:merge_status].check_state?(data[:object_attributes][:merge_status])
end
end
diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb
index 26cbfd784ad..84248f9590b 100644
--- a/app/models/project_services/gemnasium_service.rb
+++ b/app/models/project_services/gemnasium_service.rb
@@ -3,6 +3,7 @@ require "gemnasium/gitlab_service"
class GemnasiumService < Service
prop_accessor :token, :api_key
validates :token, :api_key, presence: true, if: :activated?
+ validate :deprecation_validation
def title
'Gemnasium'
@@ -27,6 +28,18 @@ class GemnasiumService < Service
%w(push)
end
+ def deprecated?
+ true
+ end
+
+ def deprecation_message
+ "Gemnasium has been acquired by GitLab in January 2018. Since May 15, 2018, the service provided by Gemnasium is no longer available."
+ end
+
+ def deprecation_validation
+ errors[:base] << deprecation_message
+ end
+
def execute(data)
return unless supported_events.include?(data[:object_kind])
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 44c6bff6b66..0e1bf11d7c0 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -596,7 +596,7 @@ class Repository
cache_method :gitlab_ci_yml
def xcode_project?
- file_on_head(:xcode_config).present?
+ file_on_head(:xcode_config, :tree).present?
end
cache_method :xcode_project?
@@ -920,11 +920,21 @@ class Repository
end
end
- def file_on_head(type)
- if head = tree(:head)
- head.blobs.find do |blob|
- Gitlab::FileDetector.type_of(blob.path) == type
+ def file_on_head(type, object_type = :blob)
+ return unless head = tree(:head)
+
+ objects =
+ case object_type
+ when :blob
+ head.blobs
+ when :tree
+ head.trees
+ else
+ raise ArgumentError, "Object type #{object_type} is not supported"
end
+
+ objects.find do |object|
+ Gitlab::FileDetector.type_of(object.path) == type
end
end
diff --git a/app/models/service.rb b/app/models/service.rb
index f7e3f7590ad..831c2ea1141 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -253,7 +253,6 @@ class Service < ActiveRecord::Base
emails_on_push
external_wiki
flowdock
- gemnasium
hipchat
irker
jira
diff --git a/app/models/user.rb b/app/models/user.rb
index 8ef3c3ceff0..0a838d34054 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -109,7 +109,7 @@ class User < ActiveRecord::Base
has_many :created_projects, foreign_key: :creator_id, class_name: 'Project'
has_many :users_star_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :starred_projects, through: :users_star_projects, source: :project
- has_many :project_authorizations
+ has_many :project_authorizations, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_many :authorized_projects, through: :project_authorizations, source: :project
has_many :user_interacted_projects
@@ -165,8 +165,7 @@ class User < ActiveRecord::Base
validate :signup_domain_valid?, on: :create, if: ->(user) { !user.created_by_id }
before_validation :sanitize_attrs
- before_validation :set_notification_email, if: :email_changed?
- before_save :set_notification_email, if: :email_changed? # in case validation is skipped
+ before_validation :set_notification_email, if: :new_record?
before_validation :set_public_email, if: :public_email_changed?
before_save :set_public_email, if: :public_email_changed? # in case validation is skipped
before_save :ensure_incoming_email_token
@@ -179,8 +178,21 @@ class User < ActiveRecord::Base
after_update :username_changed_hook, if: :username_changed?
after_destroy :post_destroy_hook
after_destroy :remove_key_cache
- after_commit :update_emails_with_primary_email, on: :update, if: -> { previous_changes.key?('email') }
- after_commit :update_invalid_gpg_signatures, on: :update, if: -> { previous_changes.key?('email') }
+ after_commit(on: :update) do
+ if previous_changes.key?('email')
+ # Grab previous_email here since previous_changes changes after
+ # #update_emails_with_primary_email and #update_notification_email are called
+ previous_email = previous_changes[:email][0]
+
+ update_emails_with_primary_email(previous_email)
+ update_invalid_gpg_signatures
+
+ if previous_email == notification_email
+ self.notification_email = email
+ save
+ end
+ end
+ end
after_initialize :set_projects_limit
@@ -546,8 +558,7 @@ class User < ActiveRecord::Base
# hash and `_was` variables getting munged.
# By using an `after_commit` instead of `after_update`, we avoid the recursive callback
# scenario, though it then requires us to use the `previous_changes` hash
- def update_emails_with_primary_email
- previous_email = previous_changes[:email][0] # grab this before the DestroyService is called
+ def update_emails_with_primary_email(previous_email)
primary_email_record = emails.find_by(email: email)
Emails::DestroyService.new(self, user: self).execute(primary_email_record) if primary_email_record
@@ -772,13 +783,13 @@ class User < ActiveRecord::Base
end
def set_notification_email
- if notification_email.blank? || !all_emails.include?(notification_email)
+ if notification_email.blank? || all_emails.exclude?(notification_email)
self.notification_email = email
end
end
def set_public_email
- if public_email.blank? || !all_emails.include?(public_email)
+ if public_email.blank? || all_emails.exclude?(public_email)
self.public_email = ''
end
end