summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorEtienne BaquƩ <ebaque@gitlab.com>2019-09-03 09:38:59 +0000
committerAndreas Brandl <abrandl@gitlab.com>2019-09-03 09:38:59 +0000
commita43ab8d6a430014e875deb3bff3fd8d8da256747 (patch)
tree25da7465575e53501737bb0d71709021173f7319 /app
parentde4e2dcafceee485cba9ef6993062b00a4929d2f (diff)
downloadgitlab-ce-a43ab8d6a430014e875deb3bff3fd8d8da256747.tar.gz
Added relationships between Release and Milestone
Modified schema via migrations. Added one-to-one relationship between the two models. Added changelog file
Diffstat (limited to 'app')
-rw-r--r--app/models/milestone.rb7
-rw-r--r--app/models/milestone_release.rb17
-rw-r--r--app/models/release.rb7
-rw-r--r--app/services/releases/concerns.rb21
-rw-r--r--app/services/releases/create_service.rb4
-rw-r--r--app/services/releases/update_service.rb3
6 files changed, 58 insertions, 1 deletions
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 2ad2838111e..101e963ea29 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -24,6 +24,12 @@ class Milestone < ApplicationRecord
belongs_to :project
belongs_to :group
+ # 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) }
@@ -59,6 +65,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_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
new file mode 100644
index 00000000000..c8743a8cad8
--- /dev/null
+++ b/app/models/milestone_release.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class MilestoneRelease < ApplicationRecord
+ belongs_to :milestone
+ belongs_to :release
+
+ validates :milestone_id, uniqueness: { scope: [:release_id] }
+ validate :same_project_between_milestone_and_release
+
+ private
+
+ def same_project_between_milestone_and_release
+ return if milestone&.project_id == release&.project_id
+
+ errors.add(:base, 'does not have the same project as the milestone')
+ end
+end
diff --git a/app/models/release.rb b/app/models/release.rb
index 459a7c29ad0..b2e65974aa0 100644
--- a/app/models/release.rb
+++ b/app/models/release.rb
@@ -12,6 +12,12 @@ class Release < ApplicationRecord
has_many :links, class_name: 'Releases::Link'
+ # 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
end
@@ -20,6 +26,7 @@ class Release < ApplicationRecord
validates :description, :project, :tag, presence: true
validates :name, presence: true, on: :create
+ validates_associated :milestone_release, message: -> (_, obj) { obj[:value].errors.full_messages.join(",") }
scope :sorted, -> { order(released_at: :desc) }
diff --git a/app/services/releases/concerns.rb b/app/services/releases/concerns.rb
index 618d96717b8..b5412e97284 100644
--- a/app/services/releases/concerns.rb
+++ b/app/services/releases/concerns.rb
@@ -47,6 +47,27 @@ module Releases
project.repository
end
end
+
+ def milestone
+ return unless params[:milestone]
+
+ strong_memoize(:milestone) do
+ MilestonesFinder.new(
+ project: project,
+ current_user: current_user,
+ project_ids: Array(project.id),
+ title: params[:milestone]
+ ).execute.first
+ end
+ end
+
+ def inexistent_milestone?
+ params[:milestone] && !params[:milestone].empty? && !milestone
+ end
+
+ def param_for_milestone_title_provided?
+ params[:milestone].present? || params[:milestone]&.empty?
+ end
end
end
end
diff --git a/app/services/releases/create_service.rb b/app/services/releases/create_service.rb
index 5b13ac631ba..c91d43084d3 100644
--- a/app/services/releases/create_service.rb
+++ b/app/services/releases/create_service.rb
@@ -7,6 +7,7 @@ module Releases
def execute
return error('Access Denied', 403) unless allowed?
return error('Release already exists', 409) if release
+ return error('Milestone does not exist', 400) if inexistent_milestone?
tag = ensure_tag
@@ -59,7 +60,8 @@ module Releases
tag: tag.name,
sha: tag.dereferenced_target.sha,
released_at: released_at,
- links_attributes: params.dig(:assets, 'links') || []
+ links_attributes: params.dig(:assets, 'links') || [],
+ milestone: milestone
)
end
end
diff --git a/app/services/releases/update_service.rb b/app/services/releases/update_service.rb
index fabfa398c59..70acc68f747 100644
--- a/app/services/releases/update_service.rb
+++ b/app/services/releases/update_service.rb
@@ -9,6 +9,9 @@ module Releases
return error('Release does not exist', 404) unless release
return error('Access Denied', 403) unless allowed?
return error('params is empty', 400) if empty_params?
+ return error('Milestone does not exist', 400) if inexistent_milestone?
+
+ params[:milestone] = milestone if param_for_milestone_title_provided?
if release.update(params)
success(tag: existing_tag, release: release)