summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/ci/artifact_blob.rb2
-rw-r--r--app/models/ci/build_metadata.rb46
-rw-r--r--app/models/clusters/applications/ingress.rb21
-rw-r--r--app/models/clusters/cluster.rb31
-rw-r--r--app/models/clusters/concerns/application_core.rb4
-rw-r--r--app/models/commit.rb1
-rw-r--r--app/models/concerns/routable.rb20
-rw-r--r--app/models/diff_note.rb13
-rw-r--r--app/models/merge_request.rb17
-rw-r--r--app/models/milestone.rb9
-rw-r--r--app/models/milestone_release.rb4
-rw-r--r--app/models/note_diff_file.rb6
-rw-r--r--app/models/project.rb12
-rw-r--r--app/models/project_services/bugzilla_service.rb2
-rw-r--r--app/models/project_services/custom_issue_tracker_service.rb2
-rw-r--r--app/models/project_services/data_fields.rb52
-rw-r--r--app/models/project_services/gitlab_issue_tracker_service.rb2
-rw-r--r--app/models/project_services/issue_tracker_data.rb3
-rw-r--r--app/models/project_services/issue_tracker_service.rb63
-rw-r--r--app/models/project_services/jira_service.rb33
-rw-r--r--app/models/project_services/jira_tracker_data.rb7
-rw-r--r--app/models/project_services/redmine_service.rb2
-rw-r--r--app/models/project_services/youtrack_service.rb2
-rw-r--r--app/models/protected_branch.rb5
-rw-r--r--app/models/release.rb9
25 files changed, 155 insertions, 213 deletions
diff --git a/app/models/ci/artifact_blob.rb b/app/models/ci/artifact_blob.rb
index ef00ad75683..d87d6a5cb2f 100644
--- a/app/models/ci/artifact_blob.rb
+++ b/app/models/ci/artifact_blob.rb
@@ -4,7 +4,7 @@ module Ci
class ArtifactBlob
include BlobLike
- EXTENSIONS_SERVED_BY_PAGES = %w[.html .htm .txt .json .xml .log].freeze
+ EXTENSIONS_SERVED_BY_PAGES = %w[.html .htm .txt .json .log].freeze
attr_reader :entry
diff --git a/app/models/ci/build_metadata.rb b/app/models/ci/build_metadata.rb
index 3097e40dd3b..4046048be1c 100644
--- a/app/models/ci/build_metadata.rb
+++ b/app/models/ci/build_metadata.rb
@@ -4,12 +4,9 @@ module Ci
# The purpose of this class is to store Build related data that can be disposed.
# Data that should be persisted forever, should be stored with Ci::Build model.
class BuildMetadata < ApplicationRecord
- BuildTimeout = Struct.new(:value, :source)
-
extend Gitlab::Ci::Model
include Presentable
include ChronicDurationAttribute
- include Gitlab::Utils::StrongMemoize
self.table_name = 'ci_builds_metadata'
@@ -31,16 +28,17 @@ module Ci
enum timeout_source: {
unknown_timeout_source: 1,
project_timeout_source: 2,
- runner_timeout_source: 3,
- job_timeout_source: 4
+ runner_timeout_source: 3
}
def update_timeout_state
- timeout = timeout_with_highest_precedence
+ return unless build.runner.present?
- return unless timeout
+ project_timeout = project&.build_timeout
+ timeout = [project_timeout, build.runner.maximum_timeout].compact.min
+ timeout_source = timeout < project_timeout ? :runner_timeout_source : :project_timeout_source
- update(timeout: timeout.value, timeout_source: timeout.source)
+ update(timeout: timeout, timeout_source: timeout_source)
end
private
@@ -48,37 +46,5 @@ module Ci
def set_build_project
self.project_id ||= self.build.project_id
end
-
- def timeout_with_highest_precedence
- [(job_timeout || project_timeout), runner_timeout].compact.min_by { |timeout| timeout.value }
- end
-
- def project_timeout
- strong_memoize(:project_timeout) do
- BuildTimeout.new(project&.build_timeout, :project_timeout_source)
- end
- end
-
- def job_timeout
- return unless build.options
-
- strong_memoize(:job_timeout) do
- if timeout_from_options = build.options[:job_timeout]
- BuildTimeout.new(timeout_from_options, :job_timeout_source)
- end
- end
- end
-
- def runner_timeout
- return unless runner_timeout_set?
-
- strong_memoize(:runner_timeout) do
- BuildTimeout.new(build.runner.maximum_timeout, :runner_timeout_source)
- end
- end
-
- def runner_timeout_set?
- build.runner&.maximum_timeout.to_i > 0
- end
end
end
diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb
index 50def3ba38c..44c66f06059 100644
--- a/app/models/clusters/applications/ingress.rb
+++ b/app/models/clusters/applications/ingress.rb
@@ -35,6 +35,10 @@ module Clusters
'stable/nginx-ingress'
end
+ def values
+ content_values.to_yaml
+ end
+
def allowed_to_uninstall?
external_ip_or_hostname? && application_jupyter_nil_or_installable?
end
@@ -67,6 +71,23 @@ module Clusters
private
+ def specification
+ return {} unless Feature.enabled?(:ingress_modsecurity)
+
+ {
+ "controller" => {
+ "config" => {
+ "enable-modsecurity" => "true",
+ "enable-owasp-modsecurity-crs" => "true"
+ }
+ }
+ }
+ end
+
+ def content_values
+ YAML.load_file(chart_values_file).deep_merge!(specification)
+ end
+
def application_jupyter_nil_or_installable?
cluster.application_jupyter.nil? || cluster.application_jupyter&.installable?
end
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index 7a61622b139..7855fb69bd6 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -37,18 +37,13 @@ module Clusters
has_one :platform_kubernetes, class_name: 'Clusters::Platforms::Kubernetes', inverse_of: :cluster, autosave: true
- def self.has_one_cluster_application(name) # rubocop:disable Naming/PredicateName
- application = APPLICATIONS[name.to_s]
- has_one application.association_name, class_name: application.to_s # rubocop:disable Rails/ReflectionClassName
- end
-
- has_one_cluster_application :helm
- has_one_cluster_application :ingress
- has_one_cluster_application :cert_manager
- has_one_cluster_application :prometheus
- has_one_cluster_application :runner
- has_one_cluster_application :jupyter
- has_one_cluster_application :knative
+ has_one :application_helm, class_name: 'Clusters::Applications::Helm'
+ has_one :application_ingress, class_name: 'Clusters::Applications::Ingress'
+ has_one :application_cert_manager, class_name: 'Clusters::Applications::CertManager'
+ has_one :application_prometheus, class_name: 'Clusters::Applications::Prometheus'
+ has_one :application_runner, class_name: 'Clusters::Applications::Runner'
+ has_one :application_jupyter, class_name: 'Clusters::Applications::Jupyter'
+ has_one :application_knative, class_name: 'Clusters::Applications::Knative'
has_many :kubernetes_namespaces
@@ -132,9 +127,15 @@ module Clusters
end
def applications
- APPLICATIONS.values.map do |application_class|
- public_send(application_class.association_name) || public_send("build_#{application_class.association_name}") # rubocop:disable GitlabSecurity/PublicSend
- end
+ [
+ application_helm || build_application_helm,
+ application_ingress || build_application_ingress,
+ application_cert_manager || build_application_cert_manager,
+ application_prometheus || build_application_prometheus,
+ application_runner || build_application_runner,
+ application_jupyter || build_application_jupyter,
+ application_knative || build_application_knative
+ ]
end
def provider
diff --git a/app/models/clusters/concerns/application_core.rb b/app/models/clusters/concerns/application_core.rb
index d1b57a21a7d..803a65726d3 100644
--- a/app/models/clusters/concerns/application_core.rb
+++ b/app/models/clusters/concerns/application_core.rb
@@ -32,10 +32,6 @@ module Clusters
self.to_s.demodulize.underscore
end
- def self.association_name
- :"application_#{application_name}"
- end
-
def name
self.class.application_name
end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index a442f607fbf..1470b50f396 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -1,3 +1,4 @@
+# coding: utf-8
# frozen_string_literal: true
class Commit
diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb
index 57118bf7a6b..8b011bca72c 100644
--- a/app/models/concerns/routable.rb
+++ b/app/models/concerns/routable.rb
@@ -33,9 +33,16 @@ module Routable
#
# Returns a single object, or nil.
def find_by_full_path(path, follow_redirects: false)
- # Case sensitive match first (it's cheaper and the usual case)
- # If we didn't have an exact match, we perform a case insensitive search
- found = includes(:route).find_by(routes: { path: path }) || where_full_path_in([path]).take
+ routable_calls_counter.increment(method: 'find_by_full_path')
+
+ if Feature.enabled?(:routable_two_step_lookup)
+ # Case sensitive match first (it's cheaper and the usual case)
+ # If we didn't have an exact match, we perform a case insensitive search
+ found = includes(:route).find_by(routes: { path: path }) || where_full_path_in([path]).take
+ else
+ order_sql = Arel.sql("(CASE WHEN routes.path = #{connection.quote(path)} THEN 0 ELSE 1 END)")
+ found = where_full_path_in([path]).reorder(order_sql).take
+ end
return found if found
@@ -54,12 +61,19 @@ module Routable
def where_full_path_in(paths)
return none if paths.empty?
+ routable_calls_counter.increment(method: 'where_full_path_in')
+
wheres = paths.map do |path|
"(LOWER(routes.path) = LOWER(#{connection.quote(path)}))"
end
includes(:route).where(wheres.join(' OR ')).references(:routes)
end
+
+ # Temporary instrumentation of method calls
+ def routable_calls_counter
+ @routable_calls_counter ||= Gitlab::Metrics.counter(:gitlab_routable_calls_total, 'Number of calls to Routable by method')
+ end
end
def full_name
diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb
index aa7286a9971..0b00cf10714 100644
--- a/app/models/diff_note.rb
+++ b/app/models/diff_note.rb
@@ -108,10 +108,13 @@ class DiffNote < Note
end
def fetch_diff_file
- return note_diff_file.raw_diff_file if note_diff_file
-
file =
- if created_at_diff?(noteable.diff_refs)
+ if note_diff_file
+ diff = Gitlab::Git::Diff.new(note_diff_file.to_hash)
+ Gitlab::Diff::File.new(diff,
+ repository: repository,
+ diff_refs: original_position.diff_refs)
+ elsif created_at_diff?(noteable.diff_refs)
# We're able to use the already persisted diffs (Postgres) if we're
# presenting a "current version" of the MR discussion diff.
# So no need to make an extra Gitaly diff request for it.
@@ -123,7 +126,9 @@ class DiffNote < Note
original_position.diff_file(repository)
end
- file&.unfold_diff_lines(position)
+ # Since persisted diff files already have its content "unfolded"
+ # there's no need to make it pass through the unfolding process.
+ file&.unfold_diff_lines(position) unless note_diff_file
file
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index ac26d29ad19..90061fe181e 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -454,17 +454,24 @@ class MergeRequest < ApplicationRecord
true
end
+ def preload_discussions_diff_highlight
+ preloadable_files = note_diff_files.for_commit_or_unresolved
+
+ discussions_diffs.load_highlight(preloadable_files.pluck(:id))
+ end
+
def discussions_diffs
strong_memoize(:discussions_diffs) do
- note_diff_files = NoteDiffFile
- .joins(:diff_note)
- .merge(notes.or(commit_notes))
- .includes(diff_note: :project)
-
Gitlab::DiscussionsDiff::FileCollection.new(note_diff_files.to_a)
end
end
+ def note_diff_files
+ NoteDiffFile
+ .where(diff_note: discussion_notes)
+ .includes(diff_note: :project)
+ end
+
def diff_size
# Calling `merge_request_diff.diffs.real_size` will also perform
# highlighting, which we don't need here.
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 800c492e8e2..4b9fee2bbdf 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -27,8 +27,11 @@ class Milestone < ApplicationRecord
belongs_to :project
belongs_to :group
- has_many :milestone_releases
- has_many :releases, through: :milestone_releases
+ # A one-to-one relationship is set up here as part of a MVC: https://gitlab.com/gitlab-org/gitlab-ce/issues/62402
+ # However, on the long term, we will want a many-to-many relationship between Release and Milestone.
+ # The "has_one through" allows us today to set up this one-to-one relationship while setting up the architecture for the long-term (ie intermediate table).
+ has_one :milestone_release
+ has_one :release, through: :milestone_release
has_internal_id :iid, scope: :project, init: ->(s) { s&.project&.milestones&.maximum(:iid) }
has_internal_id :iid, scope: :group, init: ->(s) { s&.group&.milestones&.maximum(:iid) }
@@ -65,7 +68,7 @@ class Milestone < ApplicationRecord
validate :milestone_type_check
validate :start_date_should_be_less_than_due_date, if: proc { |m| m.start_date.present? && m.due_date.present? }
validate :dates_within_4_digits
- validates_associated :milestone_releases, message: -> (_, obj) { obj[:value].map(&:errors).map(&:full_messages).join(",") }
+ validates_associated :milestone_release, message: -> (_, obj) { obj[:value].errors.full_messages.join(",") }
strip_attributes :title
diff --git a/app/models/milestone_release.rb b/app/models/milestone_release.rb
index f7127df339d..c8743a8cad8 100644
--- a/app/models/milestone_release.rb
+++ b/app/models/milestone_release.rb
@@ -4,11 +4,9 @@ class MilestoneRelease < ApplicationRecord
belongs_to :milestone
belongs_to :release
+ validates :milestone_id, uniqueness: { scope: [:release_id] }
validate :same_project_between_milestone_and_release
- # Keep until 2019-11-29
- self.ignored_columns += %i[id]
-
private
def same_project_between_milestone_and_release
diff --git a/app/models/note_diff_file.rb b/app/models/note_diff_file.rb
index 67a6d5d6d6b..fcc9e2b3fd8 100644
--- a/app/models/note_diff_file.rb
+++ b/app/models/note_diff_file.rb
@@ -3,11 +3,15 @@
class NoteDiffFile < ApplicationRecord
include DiffFile
+ scope :for_commit_or_unresolved, -> do
+ joins(:diff_note).where("resolved_at IS NULL OR noteable_type = 'Commit'")
+ end
+
scope :referencing_sha, -> (oids, project_id:) do
joins(:diff_note).where(notes: { project_id: project_id, commit_id: oids })
end
- delegate :original_position, :project, :resolved_at, to: :diff_note
+ delegate :original_position, :project, to: :diff_note
belongs_to :diff_note, inverse_of: :note_diff_file
diff --git a/app/models/project.rb b/app/models/project.rb
index 57f1ca98ee2..96c715095f6 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -58,7 +58,6 @@ class Project < ApplicationRecord
ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10
SORTING_PREFERENCE_FIELD = :projects_sort
- MAX_BUILD_TIMEOUT = 1.month
cache_markdown_field :description, pipeline: :description
@@ -431,7 +430,7 @@ class Project < ApplicationRecord
validates :build_timeout, allow_nil: true,
numericality: { greater_than_or_equal_to: 10.minutes,
- less_than: MAX_BUILD_TIMEOUT,
+ less_than: 1.month,
only_integer: true,
message: _('needs to be between 10 minutes and 1 month') }
@@ -753,15 +752,6 @@ class Project < ApplicationRecord
latest_successful_build_for_ref(job_name, ref) || raise(ActiveRecord::RecordNotFound.new("Couldn't find job #{job_name}"))
end
- def latest_pipeline_for_ref(ref = default_branch)
- ref = ref.presence || default_branch
- sha = commit(ref)&.sha
-
- return unless sha
-
- ci_pipelines.newest_first(ref: ref, sha: sha).first
- end
-
def merge_base_commit(first_commit_id, second_commit_id)
sha = repository.merge_base(first_commit_id, second_commit_id)
commit_by(oid: sha) if sha
diff --git a/app/models/project_services/bugzilla_service.rb b/app/models/project_services/bugzilla_service.rb
index 0a498fde95a..8b79b5e9f0c 100644
--- a/app/models/project_services/bugzilla_service.rb
+++ b/app/models/project_services/bugzilla_service.rb
@@ -3,6 +3,8 @@
class BugzillaService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
+ prop_accessor :project_url, :issues_url, :new_issue_url
+
def default_title
'Bugzilla'
end
diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb
index dbc42b1b86d..535fcf6b94e 100644
--- a/app/models/project_services/custom_issue_tracker_service.rb
+++ b/app/models/project_services/custom_issue_tracker_service.rb
@@ -3,6 +3,8 @@
class CustomIssueTrackerService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
+ prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
+
def default_title
'Custom Issue Tracker'
end
diff --git a/app/models/project_services/data_fields.rb b/app/models/project_services/data_fields.rb
index 0f5385f8ce2..438d85098c8 100644
--- a/app/models/project_services/data_fields.rb
+++ b/app/models/project_services/data_fields.rb
@@ -3,56 +3,8 @@
module DataFields
extend ActiveSupport::Concern
- class_methods do
- # Provide convenient accessor methods for data fields.
- # TODO: Simplify as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
- def data_field(*args)
- args.each do |arg|
- self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
- unless method_defined?(arg)
- def #{arg}
- data_fields.send('#{arg}') || (properties && properties['#{arg}'])
- end
- end
-
- def #{arg}=(value)
- @old_data_fields ||= {}
- @old_data_fields['#{arg}'] ||= #{arg} # set only on the first assignment, IOW we remember the original value only
- data_fields.send('#{arg}=', value)
- end
-
- def #{arg}_touched?
- @old_data_fields ||= {}
- @old_data_fields.has_key?('#{arg}')
- end
-
- def #{arg}_changed?
- #{arg}_touched? && @old_data_fields['#{arg}'] != #{arg}
- end
-
- def #{arg}_was
- return unless #{arg}_touched?
- return if data_fields.persisted? # arg_was does not work for attr_encrypted
-
- legacy_properties_data['#{arg}']
- end
- RUBY
- end
- end
- end
-
included do
- has_one :issue_tracker_data, autosave: true
- has_one :jira_tracker_data, autosave: true
-
- def data_fields
- raise NotImplementedError
- end
-
- def data_fields_present?
- data_fields.persisted?
- rescue NotImplementedError
- false
- end
+ has_one :issue_tracker_data
+ has_one :jira_tracker_data
end
end
diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb
index ec28602b5e6..51032932eab 100644
--- a/app/models/project_services/gitlab_issue_tracker_service.rb
+++ b/app/models/project_services/gitlab_issue_tracker_service.rb
@@ -5,6 +5,8 @@ class GitlabIssueTrackerService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
+ prop_accessor :project_url, :issues_url, :new_issue_url
+
default_value_for :default, true
def default_title
diff --git a/app/models/project_services/issue_tracker_data.rb b/app/models/project_services/issue_tracker_data.rb
index b1d67657fe6..2c1d28ed421 100644
--- a/app/models/project_services/issue_tracker_data.rb
+++ b/app/models/project_services/issue_tracker_data.rb
@@ -6,6 +6,9 @@ class IssueTrackerData < ApplicationRecord
delegate :activated?, to: :service, allow_nil: true
validates :service, presence: true
+ validates :project_url, presence: true, public_url: { enforce_sanitization: true }, if: :activated?
+ validates :issues_url, presence: true, public_url: { enforce_sanitization: true }, if: :activated?
+ validates :new_issue_url, public_url: { enforce_sanitization: true }, if: :activated?
def self.encryption_options
{
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index c201bd2ea18..b6ad46513db 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -3,14 +3,9 @@
class IssueTrackerService < Service
validate :one_issue_tracker, if: :activated?, on: :manual_change
- # TODO: we can probably just delegate as part of
- # https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
- data_field :project_url, :issues_url, :new_issue_url
-
default_value_for :category, 'issue_tracker'
- before_validation :handle_properties
- before_validation :set_default_data, on: :create
+ before_save :handle_properties
# Pattern used to extract links from comments
# Override this method on services that uses different patterns
@@ -48,31 +43,12 @@ class IssueTrackerService < Service
end
def handle_properties
- # this has been moved from initialize_properties and should be improved
- # as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
- return unless properties
-
- @legacy_properties_data = properties.dup
- data_values = properties.slice!('title', 'description')
- properties.each do |key, _|
+ properties.slice('title', 'description').each do |key, _|
current_value = self.properties.delete(key)
value = attribute_changed?(key) ? attribute_change(key).last : current_value
write_attribute(key, value)
end
-
- data_values.reject! { |key| data_fields.changed.include?(key) }
- data_fields.assign_attributes(data_values) if data_values.present?
-
- self.properties = {}
- end
-
- def legacy_properties_data
- @legacy_properties_data ||= {}
- end
-
- def data_fields
- issue_tracker_data || self.build_issue_tracker_data
end
def default?
@@ -80,7 +56,7 @@ class IssueTrackerService < Service
end
def issue_url(iid)
- issues_url.gsub(':id', iid.to_s)
+ self.issues_url.gsub(':id', iid.to_s)
end
def issue_tracker_path
@@ -104,22 +80,25 @@ class IssueTrackerService < Service
]
end
- def initialize_properties
- {}
- end
-
# Initialize with default properties values
- def set_default_data
- return unless issues_tracker.present?
-
- self.title ||= issues_tracker['title']
-
- # we don't want to override if we have set something
- return if project_url || issues_url || new_issue_url
-
- data_fields.project_url = issues_tracker['project_url']
- data_fields.issues_url = issues_tracker['issues_url']
- data_fields.new_issue_url = issues_tracker['new_issue_url']
+ # or receive a block with custom properties
+ def initialize_properties(&block)
+ return unless properties.nil?
+
+ if enabled_in_gitlab_config
+ if block_given?
+ yield
+ else
+ self.properties = {
+ title: issues_tracker['title'],
+ project_url: issues_tracker['project_url'],
+ issues_url: issues_tracker['issues_url'],
+ new_issue_url: issues_tracker['new_issue_url']
+ }
+ end
+ else
+ self.properties = {}
+ end
end
def self.supported_events
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index 61ae78a0b95..0728c83005e 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -17,10 +17,7 @@ class JiraService < IssueTrackerService
# 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.
-
- # TODO: we can probably just delegate as part of
- # https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
- data_field :username, :password, :url, :api_url, :jira_issue_transition_id
+ prop_accessor :username, :password, :url, :api_url, :jira_issue_transition_id
before_update :reset_password
@@ -38,34 +35,24 @@ class JiraService < IssueTrackerService
end
def initialize_properties
- {}
- end
-
- def data_fields
- jira_tracker_data || self.build_jira_tracker_data
+ super do
+ self.properties = {
+ url: issues_tracker['url'],
+ api_url: issues_tracker['api_url']
+ }
+ end
end
def reset_password
- data_fields.password = nil if reset_password?
- end
-
- def set_default_data
- return unless issues_tracker.present?
-
- self.title ||= issues_tracker['title']
-
- return if url
-
- data_fields.url ||= issues_tracker['url']
- data_fields.api_url ||= issues_tracker['api_url']
+ self.password = nil if reset_password?
end
def options
url = URI.parse(client_url)
{
- username: username,
- password: password,
+ username: self.username,
+ password: self.password,
site: URI.join(url, '/').to_s, # Intended to find the root
context_path: url.path,
auth_type: :basic,
diff --git a/app/models/project_services/jira_tracker_data.rb b/app/models/project_services/jira_tracker_data.rb
index e4e0f64150a..4f528e3d81b 100644
--- a/app/models/project_services/jira_tracker_data.rb
+++ b/app/models/project_services/jira_tracker_data.rb
@@ -6,6 +6,13 @@ class JiraTrackerData < ApplicationRecord
delegate :activated?, to: :service, allow_nil: true
validates :service, presence: true
+ validates :url, public_url: { enforce_sanitization: true }, presence: true, if: :activated?
+ validates :api_url, public_url: { enforce_sanitization: true }, allow_blank: true
+ validates :username, presence: true, if: :activated?
+ validates :password, presence: true, if: :activated?
+ validates :jira_issue_transition_id,
+ format: { with: Gitlab::Regex.jira_transition_id_regex, message: s_("JiraService|transition ids can have only numbers which can be split with , or ;") },
+ allow_blank: true
def self.encryption_options
{
diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb
index a4ca0d20669..5ca057ca833 100644
--- a/app/models/project_services/redmine_service.rb
+++ b/app/models/project_services/redmine_service.rb
@@ -3,6 +3,8 @@
class RedmineService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
+ prop_accessor :project_url, :issues_url, :new_issue_url
+
def default_title
'Redmine'
end
diff --git a/app/models/project_services/youtrack_service.rb b/app/models/project_services/youtrack_service.rb
index 0416eaa5be0..f9de1f7dc49 100644
--- a/app/models/project_services/youtrack_service.rb
+++ b/app/models/project_services/youtrack_service.rb
@@ -3,6 +3,8 @@
class YoutrackService < IssueTrackerService
validates :project_url, :issues_url, presence: true, public_url: true, if: :activated?
+ prop_accessor :project_url, :issues_url
+
# {PROJECT-KEY}-{NUMBER} Examples: YT-1, PRJ-1, gl-030
def self.reference_pattern(only_long: false)
if only_long
diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb
index 1857a59e01c..8769d3eb916 100644
--- a/app/models/protected_branch.rb
+++ b/app/models/protected_branch.rb
@@ -40,11 +40,6 @@ class ProtectedBranch < ApplicationRecord
def self.protected_refs(project)
project.protected_branches.select(:name)
end
-
- def self.branch_requires_code_owner_approval?(project, branch_name)
- # NOOP
- #
- end
end
ProtectedBranch.prepend_if_ee('EE::ProtectedBranch')
diff --git a/app/models/release.rb b/app/models/release.rb
index cd63b4d5fef..b2e65974aa0 100644
--- a/app/models/release.rb
+++ b/app/models/release.rb
@@ -12,8 +12,11 @@ class Release < ApplicationRecord
has_many :links, class_name: 'Releases::Link'
- has_many :milestone_releases
- has_many :milestones, through: :milestone_releases
+ # A one-to-one relationship is set up here as part of a MVC: https://gitlab.com/gitlab-org/gitlab-ce/issues/62402
+ # However, on the long term, we will want a many-to-many relationship between Release and Milestone.
+ # The "has_one through" allows us today to set up this one-to-one relationship while setting up the architecture for the long-term (ie intermediate table).
+ has_one :milestone_release
+ has_one :milestone, through: :milestone_release
default_value_for :released_at, allows_nil: false do
Time.zone.now
@@ -23,7 +26,7 @@ class Release < ApplicationRecord
validates :description, :project, :tag, presence: true
validates :name, presence: true, on: :create
- validates_associated :milestone_releases, message: -> (_, obj) { obj[:value].map(&:errors).map(&:full_messages).join(",") }
+ validates_associated :milestone_release, message: -> (_, obj) { obj[:value].errors.full_messages.join(",") }
scope :sorted, -> { order(released_at: :desc) }