summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
authorWinnie Hellmann <winnie@gitlab.com>2018-10-22 22:06:05 +0200
committerWinnie Hellmann <winnie@gitlab.com>2018-10-22 22:06:05 +0200
commit53be95daf41fc4e59deab149485210835e7e54cd (patch)
tree3f377dcc6289049581e2473b7e12f260e774784f /app/models
parent3fb7a1f97a812b7b2b5e80a8a0575cb7bfd2d3c4 (diff)
parentd6be7ed79557ce31a5d0062ceea00c877157a6c7 (diff)
downloadgitlab-ce-53be95daf41fc4e59deab149485210835e7e54cd.tar.gz
Merge branch 'master' into scheduled-manual-jobs-environment-play-buttons
Conflicts: spec/javascripts/environments/environment_actions_spec.js
Diffstat (limited to 'app/models')
-rw-r--r--app/models/application_setting.rb26
-rw-r--r--app/models/blob.rb2
-rw-r--r--app/models/ci/job_artifact.rb17
-rw-r--r--app/models/clusters/applications/jupyter.rb2
-rw-r--r--app/models/clusters/applications/runner.rb2
-rw-r--r--app/models/clusters/cluster.rb5
-rw-r--r--app/models/clusters/concerns/application_core.rb2
-rw-r--r--app/models/clusters/concerns/application_status.rb4
-rw-r--r--app/models/concerns/blob_like.rb2
-rw-r--r--app/models/concerns/relative_positioning.rb79
-rw-r--r--app/models/deployment.rb11
-rw-r--r--app/models/environment.rb2
-rw-r--r--app/models/environment_status.rb56
-rw-r--r--app/models/forked_project_link.rb6
-rw-r--r--app/models/list.rb1
-rw-r--r--app/models/project.rb39
-rw-r--r--app/models/project_services/bamboo_service.rb13
-rw-r--r--app/models/project_services/flowdock_service.rb48
-rw-r--r--app/models/project_services/jira_service.rb7
-rw-r--r--app/models/project_services/microsoft_teams_service.rb2
-rw-r--r--app/models/project_services/prometheus_service.rb9
-rw-r--r--app/models/repository.rb37
-rw-r--r--app/models/tree.rb51
-rw-r--r--app/models/user.rb4
-rw-r--r--app/models/user_callout.rb3
-rw-r--r--app/models/wiki_page.rb4
26 files changed, 241 insertions, 193 deletions
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 65a2f760f93..b66ec0ffab6 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -4,6 +4,7 @@ class ApplicationSetting < ActiveRecord::Base
include CacheableAttributes
include CacheMarkdownField
include TokenAuthenticatable
+ include IgnorableColumn
add_authentication_token_field :runners_registration_token
add_authentication_token_field :health_check_access_token
@@ -27,6 +28,14 @@ class ApplicationSetting < ActiveRecord::Base
serialize :domain_blacklist, Array # rubocop:disable Cop/ActiveRecordSerialize
serialize :repository_storages # rubocop:disable Cop/ActiveRecordSerialize
+ ignore_column :circuitbreaker_failure_count_threshold
+ ignore_column :circuitbreaker_failure_reset_time
+ ignore_column :circuitbreaker_storage_timeout
+ ignore_column :circuitbreaker_access_retries
+ ignore_column :circuitbreaker_check_interval
+ ignore_column :koding_url
+ ignore_column :koding_enabled
+
cache_markdown_field :sign_in_text
cache_markdown_field :help_page_text
cache_markdown_field :shared_runners_text, pipeline: :plain_markdown
@@ -93,10 +102,6 @@ class ApplicationSetting < ActiveRecord::Base
presence: true,
if: :unique_ips_limit_enabled
- validates :koding_url,
- presence: true,
- if: :koding_enabled
-
validates :plantuml_url,
presence: true,
if: :plantuml_enabled
@@ -150,17 +155,6 @@ class ApplicationSetting < ActiveRecord::Base
presence: true,
numericality: { greater_than_or_equal_to: 0 }
- validates :circuitbreaker_failure_count_threshold,
- :circuitbreaker_failure_reset_time,
- :circuitbreaker_storage_timeout,
- :circuitbreaker_check_interval,
- presence: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 0 }
-
- validates :circuitbreaker_access_retries,
- presence: true,
- numericality: { only_integer: true, greater_than_or_equal_to: 1 }
-
validates :gitaly_timeout_default,
presence: true,
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
@@ -256,8 +250,6 @@ class ApplicationSetting < ActiveRecord::Base
housekeeping_gc_period: 200,
housekeeping_incremental_repack_period: 10,
import_sources: Settings.gitlab['import_sources'],
- koding_enabled: false,
- koding_url: nil,
max_artifacts_size: Settings.artifacts['max_size'],
max_attachment_size: Settings.gitlab['max_attachment_size'],
mirror_available: true,
diff --git a/app/models/blob.rb b/app/models/blob.rb
index acc64ffca67..31a839274b5 100644
--- a/app/models/blob.rb
+++ b/app/models/blob.rb
@@ -162,7 +162,7 @@ class Blob < SimpleDelegator
if stored_externally?
if rich_viewer
rich_viewer.binary?
- elsif Linguist::Language.find_by_extension(name).any?
+ elsif known_extension?
false
elsif _mime_type
_mime_type.binary?
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index cb73fc74bb6..2b28b702b05 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -27,11 +27,15 @@ module Ci
metadata: :gzip,
trace: :raw,
junit: :gzip,
- codequality: :gzip,
- sast: :gzip,
- dependency_scanning: :gzip,
- container_scanning: :gzip,
- dast: :gzip
+
+ # All these file formats use `raw` as we need to store them uncompressed
+ # for Frontend to fetch the files and do analysis
+ # When they will be only used by backend, they can be `gzipped`.
+ codequality: :raw,
+ sast: :raw,
+ dependency_scanning: :raw,
+ container_scanning: :raw,
+ dast: :raw
}.freeze
belongs_to :project
@@ -100,7 +104,8 @@ module Ci
}
FILE_FORMAT_ADAPTERS = {
- gzip: Gitlab::Ci::Build::Artifacts::GzipFileAdapter
+ gzip: Gitlab::Ci::Build::Artifacts::Adapters::GzipStream,
+ raw: Gitlab::Ci::Build::Artifacts::Adapters::RawStream
}.freeze
def valid_file_format?
diff --git a/app/models/clusters/applications/jupyter.rb b/app/models/clusters/applications/jupyter.rb
index 7be6a14f585..e43a0fd1786 100644
--- a/app/models/clusters/applications/jupyter.rb
+++ b/app/models/clusters/applications/jupyter.rb
@@ -19,7 +19,7 @@ module Clusters
def set_initial_status
return unless not_installable?
- if cluster&.application_ingress_installed? && cluster.application_ingress.external_ip
+ if cluster&.application_ingress_available? && cluster.application_ingress.external_ip
self.status = 'installable'
end
end
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
index a4a2e2b79a6..43bf852c7ec 100644
--- a/app/models/clusters/applications/runner.rb
+++ b/app/models/clusters/applications/runner.rb
@@ -3,7 +3,7 @@
module Clusters
module Applications
class Runner < ActiveRecord::Base
- VERSION = '0.1.31'.freeze
+ VERSION = '0.1.34'.freeze
self.table_name = 'clusters_applications_runners'
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index d7011ef447a..20d53b8e620 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -43,8 +43,9 @@ module Clusters
delegate :active?, to: :platform_kubernetes, prefix: true, allow_nil: true
delegate :rbac?, to: :platform_kubernetes, prefix: true, allow_nil: true
- delegate :installed?, to: :application_helm, prefix: true, allow_nil: true
- delegate :installed?, to: :application_ingress, prefix: true, allow_nil: true
+ delegate :available?, to: :application_helm, prefix: true, allow_nil: true
+ delegate :available?, to: :application_ingress, prefix: true, allow_nil: true
+ delegate :available?, to: :application_prometheus, prefix: true, allow_nil: true
enum platform_type: {
kubernetes: 1
diff --git a/app/models/clusters/concerns/application_core.rb b/app/models/clusters/concerns/application_core.rb
index e3deedfb036..683b45331f6 100644
--- a/app/models/clusters/concerns/application_core.rb
+++ b/app/models/clusters/concerns/application_core.rb
@@ -15,7 +15,7 @@ module Clusters
def set_initial_status
return unless not_installable?
- self.status = 'installable' if cluster&.application_helm_installed?
+ self.status = 'installable' if cluster&.application_helm_available?
end
def self.application_name
diff --git a/app/models/clusters/concerns/application_status.rb b/app/models/clusters/concerns/application_status.rb
index a9df59fc059..93bdf9c223d 100644
--- a/app/models/clusters/concerns/application_status.rb
+++ b/app/models/clusters/concerns/application_status.rb
@@ -66,6 +66,10 @@ module Clusters
end
end
end
+
+ def available?
+ installed? || updated?
+ end
end
end
end
diff --git a/app/models/concerns/blob_like.rb b/app/models/concerns/blob_like.rb
index e96fefe81c4..f20f01486a5 100644
--- a/app/models/concerns/blob_like.rb
+++ b/app/models/concerns/blob_like.rb
@@ -2,7 +2,7 @@
module BlobLike
extend ActiveSupport::Concern
- include Linguist::BlobHelper
+ include Gitlab::BlobHelper
def id
raise NotImplementedError
diff --git a/app/models/concerns/relative_positioning.rb b/app/models/concerns/relative_positioning.rb
index 85229cded5d..045bf392ac8 100644
--- a/app/models/concerns/relative_positioning.rb
+++ b/app/models/concerns/relative_positioning.rb
@@ -12,6 +12,49 @@ module RelativePositioning
after_save :save_positionable_neighbours
end
+ class_methods do
+ def move_to_end(objects)
+ parent_ids = objects.map(&:parent_ids).flatten.uniq
+ max_relative_position = in_parents(parent_ids).maximum(:relative_position) || START_POSITION
+ objects = objects.reject(&:relative_position)
+
+ self.transaction do
+ objects.each do |object|
+ relative_position = position_between(max_relative_position, MAX_POSITION)
+ object.relative_position = relative_position
+ max_relative_position = relative_position
+ object.save
+ end
+ end
+ end
+
+ # This method takes two integer values (positions) and
+ # calculates the position between them. The range is huge as
+ # the maximum integer value is 2147483647. We are incrementing position by IDEAL_DISTANCE * 2 every time
+ # when we have enough space. If distance is less then IDEAL_DISTANCE we are calculating an average number
+ def position_between(pos_before, pos_after)
+ pos_before ||= MIN_POSITION
+ pos_after ||= MAX_POSITION
+
+ pos_before, pos_after = [pos_before, pos_after].sort
+
+ halfway = (pos_after + pos_before) / 2
+ distance_to_halfway = pos_after - halfway
+
+ if distance_to_halfway < IDEAL_DISTANCE
+ halfway
+ else
+ if pos_before == MIN_POSITION
+ pos_after - IDEAL_DISTANCE
+ elsif pos_after == MAX_POSITION
+ pos_before + IDEAL_DISTANCE
+ else
+ halfway
+ end
+ end
+ end
+ end
+
def min_relative_position
self.class.in_parents(parent_ids).minimum(:relative_position)
end
@@ -57,7 +100,7 @@ module RelativePositioning
@positionable_neighbours = [before] # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
- self.relative_position = position_between(before.relative_position, after.relative_position)
+ self.relative_position = self.class.position_between(before.relative_position, after.relative_position)
end
def move_after(before = self)
@@ -72,7 +115,7 @@ module RelativePositioning
pos_after = issue_to_move.relative_position
end
- self.relative_position = position_between(pos_before, pos_after)
+ self.relative_position = self.class.position_between(pos_before, pos_after)
end
def move_before(after = self)
@@ -87,15 +130,15 @@ module RelativePositioning
pos_before = issue_to_move.relative_position
end
- self.relative_position = position_between(pos_before, pos_after)
+ self.relative_position = self.class.position_between(pos_before, pos_after)
end
def move_to_end
- self.relative_position = position_between(max_relative_position || START_POSITION, MAX_POSITION)
+ self.relative_position = self.class.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)
+ self.relative_position = self.class.position_between(min_relative_position || START_POSITION, MIN_POSITION)
end
# Indicates if there is an issue that should be shifted to free the place
@@ -112,32 +155,6 @@ module RelativePositioning
private
- # This method takes two integer values (positions) and
- # calculates the position between them. The range is huge as
- # the maximum integer value is 2147483647. We are incrementing position by IDEAL_DISTANCE * 2 every time
- # when we have enough space. If distance is less then IDEAL_DISTANCE we are calculating an average number
- def position_between(pos_before, pos_after)
- pos_before ||= MIN_POSITION
- pos_after ||= MAX_POSITION
-
- pos_before, pos_after = [pos_before, pos_after].sort
-
- halfway = (pos_after + pos_before) / 2
- distance_to_halfway = pos_after - halfway
-
- if distance_to_halfway < IDEAL_DISTANCE
- halfway
- else
- if pos_before == MIN_POSITION
- pos_after - IDEAL_DISTANCE
- elsif pos_after == MAX_POSITION
- pos_before + IDEAL_DISTANCE
- else
- halfway
- end
- end
- end
-
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def save_positionable_neighbours
return unless @positionable_neighbours
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index ed61135cb47..f1bce1a1daf 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -19,6 +19,17 @@ class Deployment < ActiveRecord::Base
after_create :create_ref
after_create :invalidate_cache
+ scope :for_environment, -> (environment) { where(environment_id: environment) }
+
+ def self.last_for_environment(environment)
+ ids = self
+ .for_environment(environment)
+ .select('MAX(id) AS id')
+ .group(:environment_id)
+ .map(&:id)
+ find(ids)
+ end
+
def commit
project.commit(sha)
end
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 309bd4f37c9..0816c395185 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -48,6 +48,8 @@ class Environment < ActiveRecord::Base
order(Gitlab::Database.nulls_first_order("(#{max_deployment_id_sql})", 'ASC'))
end
scope :in_review_folder, -> { where(environment_type: "review") }
+ scope :for_name, -> (name) { where(name: name) }
+ scope :for_project, -> (project) { where(project_id: project) }
state_machine :state, initial: :available do
event :start do
diff --git a/app/models/environment_status.rb b/app/models/environment_status.rb
new file mode 100644
index 00000000000..5ff3acc0e58
--- /dev/null
+++ b/app/models/environment_status.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+class EnvironmentStatus
+ include Gitlab::Utils::StrongMemoize
+
+ attr_reader :environment, :merge_request
+
+ delegate :id, to: :environment
+ delegate :name, to: :environment
+ delegate :project, to: :environment
+ delegate :deployed_at, to: :deployment, allow_nil: true
+
+ def initialize(environment, merge_request)
+ @environment = environment
+ @merge_request = merge_request
+ end
+
+ def deployment
+ strong_memoize(:deployment) do
+ environment.first_deployment_for(merge_request.diff_head_sha)
+ end
+ end
+
+ def deployed_at
+ deployment&.created_at
+ end
+
+ def changes
+ sha = merge_request.diff_head_sha
+ return [] if project.route_map_for(sha).nil?
+
+ changed_files.map { |file| build_change(file, sha) }.compact
+ end
+
+ def changed_files
+ merge_request.merge_request_diff
+ .merge_request_diff_files.where(deleted_file: false)
+ end
+
+ private
+
+ PAGE_EXTENSIONS = /\A\.(s?html?|php|asp|cgi|pl)\z/i.freeze
+
+ def build_change(file, sha)
+ public_path = project.public_path_for_source_path(file.new_path, sha)
+ return if public_path.nil?
+
+ ext = File.extname(public_path)
+ return if ext.present? && ext !~ PAGE_EXTENSIONS
+
+ {
+ path: public_path,
+ external_url: environment.external_url_for(file.new_path, sha)
+ }
+ end
+end
diff --git a/app/models/forked_project_link.rb b/app/models/forked_project_link.rb
deleted file mode 100644
index 0f7067238cd..00000000000
--- a/app/models/forked_project_link.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# frozen_string_literal: true
-
-class ForkedProjectLink < ActiveRecord::Base
- belongs_to :forked_to_project, -> { where.not(pending_delete: true) }, class_name: 'Project'
- belongs_to :forked_from_project, -> { where.not(pending_delete: true) }, class_name: 'Project'
-end
diff --git a/app/models/list.rb b/app/models/list.rb
index 1a30acc83cf..029685be927 100644
--- a/app/models/list.rb
+++ b/app/models/list.rb
@@ -15,6 +15,7 @@ class List < ActiveRecord::Base
scope :destroyable, -> { where(list_type: list_types.slice(*destroyable_types).values) }
scope :movable, -> { where(list_type: list_types.slice(*movable_types).values) }
+ scope :preload_associations, -> { preload(:board, :label) }
class << self
def destroyable_types
diff --git a/app/models/project.rb b/app/models/project.rb
index 05e14c578b5..4798fae82b7 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -49,8 +49,11 @@ class Project < ActiveRecord::Base
attachments: 2
}.freeze
- # Valids ports to import from
- VALID_IMPORT_PORTS = [22, 80, 443].freeze
+ VALID_IMPORT_PORTS = [80, 443].freeze
+ VALID_IMPORT_PROTOCOLS = %w(http https git).freeze
+
+ VALID_MIRROR_PORTS = [22, 80, 443].freeze
+ VALID_MIRROR_PROTOCOLS = %w(http https ssh git).freeze
cache_markdown_field :description, pipeline: :description
@@ -164,20 +167,15 @@ class Project < ActiveRecord::Base
has_one :packagist_service
has_one :hangouts_chat_service
- # TODO: replace these relations with the fork network versions
- has_one :forked_project_link, foreign_key: "forked_to_project_id"
- has_one :forked_from_project, through: :forked_project_link
-
- has_many :forked_project_links, foreign_key: "forked_from_project_id"
- has_many :forks, through: :forked_project_links, source: :forked_to_project
- # TODO: replace these relations with the fork network versions
-
has_one :root_of_fork_network,
foreign_key: 'root_project_id',
inverse_of: :root_project,
class_name: 'ForkNetwork'
has_one :fork_network_member
has_one :fork_network, through: :fork_network_member
+ has_one :forked_from_project, through: :fork_network_member
+ has_many :forked_to_members, class_name: 'ForkNetworkMember', foreign_key: 'forked_from_project_id'
+ has_many :forks, through: :forked_to_members, source: :project, inverse_of: :forked_from_project
has_one :import_state, autosave: true, class_name: 'ProjectImportState', inverse_of: :project
has_one :import_export_upload, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
@@ -305,10 +303,10 @@ class Project < ActiveRecord::Base
validates :namespace, presence: true
validates :name, uniqueness: { scope: :namespace_id }
- validates :import_url, url: { protocols: %w(http https ssh git),
+ validates :import_url, url: { protocols: ->(project) { project.persisted? ? VALID_MIRROR_PROTOCOLS : VALID_IMPORT_PROTOCOLS },
+ ports: ->(project) { project.persisted? ? VALID_MIRROR_PORTS : VALID_IMPORT_PORTS },
allow_localhost: false,
- enforce_user: true,
- ports: VALID_IMPORT_PORTS }, if: [:external_import?, :import_url_changed?]
+ enforce_user: true }, if: [:external_import?, :import_url_changed?]
validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create
validate :check_repository_path_availability, on: :update, if: ->(project) { project.renamed? }
@@ -690,6 +688,8 @@ class Project < ActiveRecord::Base
else
super
end
+ rescue
+ super
end
def valid_import_url?
@@ -1247,12 +1247,7 @@ class Project < ActiveRecord::Base
end
def forked?
- return true if fork_network && fork_network.root_project != self
-
- # TODO: Use only the above conditional using the `fork_network`
- # This is the old conditional that looks at the `forked_project_link`, we
- # fall back to this while we're migrating the new models
- !(forked_project_link.nil? || forked_project_link.forked_from_project.nil?)
+ fork_network && fork_network.root_project != self
end
def fork_source
@@ -1543,9 +1538,7 @@ class Project < ActiveRecord::Base
def visibility_level_allowed_as_fork?(level = self.visibility_level)
return true unless forked?
- # self.forked_from_project will be nil before the project is saved, so
- # we need to go through the relation
- original_project = forked_project_link&.forked_from_project
+ original_project = fork_source
return true unless original_project
level <= original_project.visibility_level
@@ -1789,7 +1782,7 @@ class Project < ActiveRecord::Base
return unless export_file_exists?
import_export_upload.remove_export_file!
- import_export_upload.save
+ import_export_upload.save unless import_export_upload.destroyed?
end
def export_file_exists?
diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb
index d502423726c..d121d088ff6 100644
--- a/app/models/project_services/bamboo_service.rb
+++ b/app/models/project_services/bamboo_service.rb
@@ -80,13 +80,18 @@ class BambooService < CiService
private
+ def get_build_result_index
+ # When Bamboo returns multiple results for a given changeset, arbitrarily assume the most relevant result to be the last one.
+ -1
+ end
+
def read_build_page(response)
- if response.code != 200 || response['results']['results']['size'] == '0'
+ if response.code != 200 || response.dig('results', 'results', 'size') == '0'
# If actual build link can't be determined, send user to build summary page.
URI.join("#{bamboo_url}/", "browse/#{build_key}").to_s
else
# If actual build link is available, go to build result page.
- result_key = response['results']['results']['result']['planResultKey']['key']
+ result_key = response.dig('results', 'results', 'result', get_build_result_index, 'planResultKey', 'key')
URI.join("#{bamboo_url}/", "browse/#{result_key}").to_s
end
end
@@ -94,10 +99,10 @@ class BambooService < CiService
def read_commit_status(response)
return :error unless response.code == 200 || response.code == 404
- status = if response.code == 404 || response['results']['results']['size'] == '0'
+ status = if response.code == 404 || response.dig('results', 'results', 'size') == '0'
'Pending'
else
- response['results']['results']['result']['buildState']
+ response.dig('results', 'results', 'result', get_build_result_index, 'buildState')
end
if status.include?('Success')
diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb
index 2545df06f6b..76624263aab 100644
--- a/app/models/project_services/flowdock_service.rb
+++ b/app/models/project_services/flowdock_service.rb
@@ -1,53 +1,5 @@
# frozen_string_literal: true
-require "flowdock-git-hook"
-
-# Flow dock depends on Grit to compute the number of commits between two given
-# commits. To make this depend on Gitaly, a monkey patch is applied
-module Flowdock
- class Git
- # pass down a Repository all the way down
- def repo
- @options[:repo]
- end
-
- def config
- {}
- end
-
- def messages
- Git::Builder.new(repo: repo,
- ref: @ref,
- before: @from,
- after: @to,
- commit_url: @commit_url,
- branch_url: @branch_url,
- diff_url: @diff_url,
- repo_url: @repo_url,
- repo_name: @repo_name,
- permanent_refs: @permanent_refs,
- tags: tags
- ).to_hashes
- end
-
- class Builder
- def commits
- @repo.commits_between(@before, @after).map do |commit|
- {
- url: @opts[:commit_url] ? @opts[:commit_url] % [commit.sha] : nil,
- id: commit.sha,
- message: commit.message,
- author: {
- name: commit.author_name,
- email: commit.author_email
- }
- }
- end
- end
- end
- end
-end
-
class FlowdockService < Service
prop_accessor :token
validates :token, presence: true, if: :activated?
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index ba7fcb0cf93..5a38f48c542 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -14,6 +14,9 @@ class JiraService < IssueTrackerService
format: { with: Gitlab::Regex.jira_transition_id_regex, message: "transition ids can have only numbers which can be split with , or ;" },
allow_blank: true
+ # JIRA cloud version is deprecating authentication via username and password.
+ # We should use username/password for JIRA server and email/api_token for JIRA cloud,
+ # for more information check: https://gitlab.com/gitlab-org/gitlab-ce/issues/49936.
prop_accessor :username, :password, :url, :api_url, :jira_issue_transition_id, :title, :description
before_update :reset_password
@@ -95,8 +98,8 @@ class JiraService < IssueTrackerService
[
{ type: 'text', name: 'url', title: 'Web URL', placeholder: 'https://jira.example.com', required: true },
{ type: 'text', name: 'api_url', title: 'JIRA API URL', placeholder: 'If different from Web URL' },
- { type: 'text', name: 'username', placeholder: '', required: true },
- { type: 'password', name: 'password', placeholder: '', required: true },
+ { type: 'text', name: 'username', title: 'Username or Email', placeholder: 'Use a username for server version and an email for cloud version', required: true },
+ { type: 'password', name: 'password', title: 'Password or API token', placeholder: 'Use a password for server version and an API token for cloud version', required: true },
{ type: 'text', name: 'jira_issue_transition_id', title: 'Transition ID(s)', placeholder: 'Use , or ; to separate multiple transition IDs' }
]
end
diff --git a/app/models/project_services/microsoft_teams_service.rb b/app/models/project_services/microsoft_teams_service.rb
index 5b0e5fed092..c34078f13c1 100644
--- a/app/models/project_services/microsoft_teams_service.rb
+++ b/app/models/project_services/microsoft_teams_service.rb
@@ -17,7 +17,7 @@ class MicrosoftTeamsService < ChatNotificationService
'This service sends notifications about projects events to Microsoft Teams channels.<br />
To set up this service:
<ol>
- <li><a href="https://msdn.microsoft.com/en-us/microsoft-teams/connectors">Getting started with 365 Office Connectors For Microsoft Teams</a>.</li>
+ <li><a href="https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/connectors/connectors-using#setting-up-a-custom-incoming-webhook">Setup a custom Incoming Webhook using Office 365 Connectors For Microsoft Teams</a>.</li>
<li>Paste the <strong>Webhook URL</strong> into the field below.</li>
<li>Select events below to enable notifications.</li>
</ol>'
diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb
index 509e5b6089b..211e5c3fcbf 100644
--- a/app/models/project_services/prometheus_service.rb
+++ b/app/models/project_services/prometheus_service.rb
@@ -26,7 +26,7 @@ class PrometheusService < MonitoringService
end
def editable?
- manual_configuration? || !prometheus_installed?
+ manual_configuration? || !prometheus_available?
end
def title
@@ -56,7 +56,6 @@ class PrometheusService < MonitoringService
name: 'api_url',
title: 'API URL',
placeholder: s_('PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/'),
- help: s_('PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server.'),
required: true
}
]
@@ -75,17 +74,17 @@ class PrometheusService < MonitoringService
RestClient::Resource.new(api_url) if api_url && manual_configuration? && active?
end
- def prometheus_installed?
+ def prometheus_available?
return false if template?
return false unless project
- project.clusters.enabled.any? { |cluster| cluster.application_prometheus&.installed? }
+ project.clusters.enabled.any? { |cluster| cluster.application_prometheus_available? }
end
private
def synchronize_service_state
- self.active = prometheus_installed? || manual_configuration?
+ self.active = prometheus_available? || manual_configuration?
true
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index a3a3ce179fc..37a1dd64052 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -36,7 +36,7 @@ class Repository
# For example, for entry `:commit_count` there's a method called `commit_count` which
# stores its data in the `commit_count` cache key.
CACHED_METHODS = %i(size commit_count rendered_readme contribution_guide
- changelog license_blob license_key gitignore koding_yml
+ changelog license_blob license_key gitignore
gitlab_ci_yml branch_names tag_names branch_count
tag_count avatar exists? root_ref has_visible_content?
issue_template_names merge_request_template_names xcode_project?).freeze
@@ -53,7 +53,6 @@ class Repository
license: %i(license_blob license_key license),
contributing: :contribution_guide,
gitignore: :gitignore,
- koding: :koding_yml,
gitlab_ci: :gitlab_ci_yml,
avatar: :avatar,
issue_template: :issue_template_names,
@@ -488,7 +487,20 @@ class Repository
end
def blob_at(sha, path)
- Blob.decorate(raw_repository.blob_at(sha, path), project)
+ blob = Blob.decorate(raw_repository.blob_at(sha, path), project)
+
+ # Don't attempt to return a special result if there is no blob at all
+ return unless blob
+
+ # Don't attempt to return a special result unless we're looking at HEAD
+ return blob unless head_commit&.sha == sha
+
+ case path
+ when head_tree&.readme_path
+ ReadmeBlob.new(blob, self)
+ else
+ blob
+ end
rescue Gitlab::Git::Repository::NoRepository
nil
end
@@ -570,9 +582,7 @@ class Repository
cache_method :merge_request_template_names, fallback: []
def readme
- if readme = tree(:head)&.readme
- ReadmeBlob.new(readme, self)
- end
+ head_tree&.readme
end
def rendered_readme
@@ -619,11 +629,6 @@ class Repository
end
cache_method :gitignore
- def koding_yml
- file_on_head(:koding)
- end
- cache_method :koding_yml
-
def gitlab_ci_yml
file_on_head(:gitlab_ci)
end
@@ -881,10 +886,12 @@ class Repository
delegate :merged_branch_names, to: :raw_repository
- def merge_base(first_commit_id, second_commit_id)
- first_commit_id = commit(first_commit_id).try(:id) || first_commit_id
- second_commit_id = commit(second_commit_id).try(:id) || second_commit_id
- raw_repository.merge_base(first_commit_id, second_commit_id)
+ def merge_base(*commits_or_ids)
+ commit_ids = commits_or_ids.map do |commit_or_id|
+ commit_or_id.is_a?(::Commit) ? commit_or_id.id : commit_or_id
+ end
+
+ raw_repository.merge_base(*commit_ids)
end
def ancestor?(ancestor_id, descendant_id)
diff --git a/app/models/tree.rb b/app/models/tree.rb
index 3641c33254c..cd385872171 100644
--- a/app/models/tree.rb
+++ b/app/models/tree.rb
@@ -2,6 +2,7 @@
class Tree
include Gitlab::MarkupHelper
+ include Gitlab::Utils::StrongMemoize
attr_accessor :repository, :sha, :path, :entries
@@ -16,32 +17,36 @@ class Tree
@entries = Gitlab::Git::Tree.where(git_repo, @sha, @path, recursive)
end
- def readme
- return @readme if defined?(@readme)
-
- available_readmes = blobs.select do |blob|
- Gitlab::FileDetector.type_of(blob.name) == :readme
- end
-
- previewable_readmes = available_readmes.select do |blob|
- previewable?(blob.name)
- end
-
- plain_readmes = available_readmes.select do |blob|
- plain?(blob.name)
+ def readme_path
+ strong_memoize(:readme_path) do
+ available_readmes = blobs.select do |blob|
+ Gitlab::FileDetector.type_of(blob.name) == :readme
+ end
+
+ previewable_readmes = available_readmes.select do |blob|
+ previewable?(blob.name)
+ end
+
+ plain_readmes = available_readmes.select do |blob|
+ plain?(blob.name)
+ end
+
+ # Prioritize previewable over plain readmes
+ entry = previewable_readmes.first || plain_readmes.first
+ next nil unless entry
+
+ if path == '/'
+ entry.name
+ else
+ File.join(path, entry.name)
+ end
end
+ end
- # Prioritize previewable over plain readmes
- readme_tree = previewable_readmes.first || plain_readmes.first
-
- # Return if we can't preview any of them
- if readme_tree.nil?
- return @readme = nil
+ def readme
+ strong_memoize(:readme) do
+ repository.blob_at(sha, readme_path) if readme_path
end
-
- readme_path = path == '/' ? readme_tree.name : File.join(path, readme_tree.name)
-
- @readme = repository.blob_at(sha, readme_path)
end
def trees
diff --git a/app/models/user.rb b/app/models/user.rb
index 8a7acfb73b1..34efb22b359 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -217,7 +217,7 @@ class User < ActiveRecord::Base
# User's Dashboard preference
# Note: When adding an option, it MUST go on the end of the array.
- enum dashboard: [:projects, :stars, :project_activity, :starred_project_activity, :groups, :todos, :issues, :merge_requests]
+ enum dashboard: [:projects, :stars, :project_activity, :starred_project_activity, :groups, :todos, :issues, :merge_requests, :operations]
# User's Project preference
# Note: When adding an option, it MUST go on the end of the array.
@@ -264,7 +264,7 @@ class User < ActiveRecord::Base
scope :order_recent_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'DESC')) }
scope :order_oldest_sign_in, -> { reorder(Gitlab::Database.nulls_last_order('current_sign_in_at', 'ASC')) }
scope :confirmed, -> { where.not(confirmed_at: nil) }
- scope :by_username, -> (usernames) { iwhere(username: usernames) }
+ scope :by_username, -> (usernames) { iwhere(username: Array(usernames).map(&:to_s)) }
scope :for_todos, -> (todos) { where(id: todos.select(:user_id)) }
# Limits the users to those that have TODOs, optionally in the given state.
diff --git a/app/models/user_callout.rb b/app/models/user_callout.rb
index 2c0e8659fc1..1cd05cf3aac 100644
--- a/app/models/user_callout.rb
+++ b/app/models/user_callout.rb
@@ -6,8 +6,7 @@ class UserCallout < ActiveRecord::Base
enum feature_name: {
gke_cluster_integration: 1,
gcp_signup_offer: 2,
- cluster_security_warning: 3,
- gold_trial: 4
+ cluster_security_warning: 3
}
validates :user, presence: true
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index 42fd213d03b..c5e349ae913 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -160,7 +160,9 @@ class WikiPage
# Returns boolean True or False if this instance
# is an old version of the page.
def historical?
- @page.historical? && last_version.sha != version.sha
+ return false unless last_commit_sha && version
+
+ @page.historical? && last_commit_sha != version.sha
end
# Returns boolean True or False if this instance