Skip to content
Snippets Groups Projects
Commit 584e5324 authored by Sean Carroll's avatar Sean Carroll :rocket:
Browse files

Support Group Milestones to be associated with Project Releases in API

Part of #235391

See merge request !43385
parent 873adef4
No related branches found
No related tags found
No related merge requests found
......@@ -14,3 +14,5 @@ def same_project_between_milestone_and_release
errors.add(:base, _('Release does not have the same project as the milestone'))
end
end
MilestoneRelease.prepend_if_ee('EE::MilestoneRelease')
......@@ -63,6 +63,7 @@ def milestones
project: project,
current_user: current_user,
project_ids: Array(project.id),
group_ids: project_group_id,
state: 'all',
title: params[:milestones]
).execute
......@@ -79,5 +80,10 @@ def inexistent_milestones
def param_for_milestone_titles_provided?
params.key?(:milestones)
end
# overridden in EE
def project_group_id; end
end
end
Releases::BaseService.prepend_if_ee('EE::Releases::BaseService')
......@@ -12,7 +12,7 @@ def execute
summary = ::Evidences::EvidenceSerializer.new.represent(evidence, evidence_options) # rubocop: disable CodeReuse/Serializer
evidence.summary = summary
# TODO: fix the sha generating https://gitlab.com/gitlab-org/gitlab/-/issues/209000
# TODO: fix the sha generation https://gitlab.com/groups/gitlab-org/-/epics/3683
evidence.summary_sha = Gitlab::CryptoHelper.sha256(summary)
evidence.save!
......
# frozen_string_literal: true
module EE
module MilestoneRelease
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
prepended do
validate :same_project_between_project_milestone_and_group
def same_project_between_milestone_and_release
return unless milestone&.project_id
return if milestone.project_id == release&.project_id
errors.add(:base, _('Release does not have the same project as the milestone'))
end
def same_project_between_project_milestone_and_group
return unless milestone&.group_id
return if milestone.group.projects.map(&:id).include?(release&.project_id)
errors.add(:base, _('Release does not have the same project as the milestone'))
end
end
end
end
# frozen_string_literal: true
module EE
module Releases
module BaseService
extend ActiveSupport::Concern
extend ::Gitlab::Utils::Override
prepended do
def project_group_id
project.group&.id
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe MilestoneRelease do
let(:project) { create(:project) }
let(:release) { create(:release, project: project) }
describe 'validations' do
let(:milestone_release) { build(:milestone_release, release: release, milestone: milestone) }
context 'when it is a project milestone' do
context 'when milestone and release have the same project' do
let(:milestone) { create(:milestone, project: project, group: nil) }
it 'is valid' do
expect(milestone_release).to be_valid
end
end
context 'when milestone and release do not have the same project' do
let(:milestone) { create(:milestone, project: create(:project), group: nil) }
it 'is not valid' do
expect(milestone_release).not_to be_valid
end
end
end
context 'when it is a group milestone' do
let(:milestone) { create(:milestone, project: nil, group: group) }
context 'when group and release have the same project' do
let(:group) { create(:group) }
let(:project) { create(:project, group: group) }
it 'is valid' do
expect(milestone_release).to be_valid
end
end
context 'when milestone and group do not have the same project' do
let(:group) { create(:group) }
let(:project2) { create(:project, group: group) }
it 'is not valid' do
expect(milestone_release).not_to be_valid
end
end
context 'when it is a supergroup milestone' do
let(:supergroup) { create(:group) }
let(:group) { create(:group, parent: supergroup) }
let(:project) { create(:project, group: group) }
let(:milestone) { create(:milestone, project: nil, group: supergroup) }
it 'is not valid' do
expect(milestone_release).not_to be_valid
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Releases::CreateService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:tag_name) { project.repository.tag_names.first }
let(:tag_sha) { project.repository.find_tag(tag_name).dereferenced_target.sha }
let(:name) { 'Bionic Beaver' }
let(:description) { 'Awesome release!' }
let(:params) { { tag: tag_name, name: name, description: description, ref: ref } }
let(:ref) { nil }
let(:service) { described_class.new(project, user, params) }
let(:release) { Release.last }
before do
project.add_maintainer(user)
end
describe 'group milestones' do
context 'when a group milestone is passed' do
let(:group) { create :group }
let(:group_milestone) { create(:milestone, group: group, title: 'g1') }
let(:params_with_milestones) { params.merge!({ milestones: [group_milestone.title] }) }
it 'adds the group milestone' do
service.execute
expect(release.milestones).to match_array([group_milestone])
end
end
context 'when a supergroup milestone is passed' do
let(:group) { create(:group, parent: supergroup) }
let(:supergroup) { create(:group) }
let(:supergroup_milestone) { create(:milestone, group: supergroup, title: 'sg1') }
let(:params_with_milestones) { params.merge!({ milestones: [supergroup_milestone.title] }) }
it 'ignores the milestone' do
service.execute
expect(release.milestones).to match_array([])
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Releases::UpdateService do
let(:group) { create(:group) }
let(:project) { create(:project, :repository, group: group) }
let(:user) { create(:user) }
let(:new_name) { 'A new name' }
let(:new_description) { 'The best release!' }
let(:params) { { name: new_name, description: new_description, tag: tag_name } }
let!(:release) { create(:release, project: project, author: user, tag: tag_name) }
let(:tag_name) { 'v1.1.0' }
let(:service) { described_class.new(project, user, params_with_milestones) }
before do
project.add_developer(user)
end
describe 'group milestones' do
context 'when a group milestone is passed' do
let(:group_milestone) { create(:milestone, group: group, title: 'g1') }
let(:params_with_milestones) { params.merge!({ milestones: [group_milestone.title] }) }
context 'when there is no project milestone' do
it 'adds the group milestone' do
result = service.execute
release.reload
expect(release.milestones).to match_array([group_milestone])
expect(result[:milestones_updated]).to be_truthy
end
end
context 'when there is an existing project milestone' do
let(:project_milestone) { create(:milestone, project: project, title: 'p1') }
before do
release.milestones << project_milestone
end
it 'replaces the project milestone with the group milestone' do
result = service.execute
release.reload
expect(release.milestones).to match_array([group_milestone])
expect(result[:milestones_updated]).to be_truthy
end
end
context 'when an empty milestone array is passed' do
let(:project_milestone) { create(:milestone, project: project, title: 'p1') }
let(:params_with_milestones) { params.merge!({ milestones: [] }) }
before do
release.milestones << project_milestone
end
it 'clears the milestone array' do
result = service.execute
release.reload
expect(release.milestones).to match_array([])
expect(result[:milestones_updated]).to be_truthy
end
end
context 'when a supergroup milestone is passed' do
let(:group) { create(:group, parent: supergroup) }
let(:supergroup) { create(:group) }
let(:supergroup_milestone) { create(:milestone, group: supergroup, title: 'sg1') }
let(:params_with_milestones) { params.merge!({ milestones: [supergroup_milestone.title] }) }
it 'ignores the milestone' do
service.execute
release.reload
expect(release.milestones).to match_array([])
end
end
end
end
end
......@@ -816,6 +816,43 @@
expect(json_response['message']).to eq("Milestone(s) not found: v1.0")
end
end
context 'with a group milestone' do
let(:project) { create(:project, :repository, group: group) }
let(:group) { create(:group) }
let(:group_milestone) { create(:milestone, group: group, title: 'g1') }
context 'when a group milestone is passed' do
let(:milestone_params) { { milestones: [group_milestone.title] } }
it 'adds the milestone' do
expect(response).to have_gitlab_http_status(:created)
expect(json_response['milestones'].map {|m| m['title']}).to match_array(['g1'])
end
end
context 'when group and project milestones are passed' do
let(:project_milestone) { create(:milestone, project: project, title: 'v1.0') }
let(:milestone_params) { { milestones: [group_milestone.title, project_milestone.title] } }
it 'adds the milestone' do
expect(response).to have_gitlab_http_status(:created)
expect(json_response['milestones'].map {|m| m['title']}).to match_array(['g1', 'v1.0'])
end
end
end
context 'with a supergroup milestone' do
let(:group) { create(:group, parent: supergroup) }
let(:supergroup) { create(:group) }
let(:supergroup_milestone) { create(:milestone, group: supergroup, title: 'sg1') }
let(:milestone_params) { params.merge!({ milestones: [supergroup_milestone.title] }) }
it 'returns a 400 error as milestone not found' do
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to eq("Milestone(s) not found: sg1")
end
end
end
end
......@@ -998,6 +1035,40 @@
end
end
end
context 'group milestones' do
let(:project) { create(:project, :repository, group: group) }
let(:group) { create(:group) }
context 'when a group milestone is passed' do
let(:group_milestone) { create(:milestone, group: group, title: 'g1') }
let(:params) { { milestones: [group_milestone.title] } }
context 'when there is no project milestone' do
it 'adds the group milestone' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['milestones'].map {|m| m['title']}).to match_array([group_milestone.title])
end
end
context 'when there is an existing project milestone' do
let(:project_milestone) { create(:milestone, project: project, title: 'p1') }
before do
release.milestones << project_milestone
end
it 'replaces the project milestone with the group milestone' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['milestones'].map {|m| m['title']}).to match_array([group_milestone.title])
end
end
end
end
end
end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment