diff options
author | Etienne BaquƩ <ebaque@gitlab.com> | 2019-09-03 09:38:59 +0000 |
---|---|---|
committer | Andreas Brandl <abrandl@gitlab.com> | 2019-09-03 09:38:59 +0000 |
commit | a43ab8d6a430014e875deb3bff3fd8d8da256747 (patch) | |
tree | 25da7465575e53501737bb0d71709021173f7319 /spec | |
parent | de4e2dcafceee485cba9ef6993062b00a4929d2f (diff) | |
download | gitlab-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 'spec')
-rw-r--r-- | spec/factories/milestone_releases.rb | 14 | ||||
-rw-r--r-- | spec/fixtures/api/schemas/public_api/v4/release.json | 1 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/all_models.yml | 7 | ||||
-rw-r--r-- | spec/models/milestone_release_spec.rb | 36 | ||||
-rw-r--r-- | spec/models/milestone_spec.rb | 20 | ||||
-rw-r--r-- | spec/models/release_spec.rb | 15 | ||||
-rw-r--r-- | spec/services/milestones/destroy_service_spec.rb | 14 | ||||
-rw-r--r-- | spec/services/releases/create_service_spec.rb | 62 | ||||
-rw-r--r-- | spec/services/releases/destroy_service_spec.rb | 10 | ||||
-rw-r--r-- | spec/services/releases/update_service_spec.rb | 37 |
10 files changed, 216 insertions, 0 deletions
diff --git a/spec/factories/milestone_releases.rb b/spec/factories/milestone_releases.rb new file mode 100644 index 00000000000..08e109480ab --- /dev/null +++ b/spec/factories/milestone_releases.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :milestone_release do + milestone + release + + before(:create, :build) do |mr| + project = create(:project) + mr.milestone.project = project + mr.release.project = project + end + end +end diff --git a/spec/fixtures/api/schemas/public_api/v4/release.json b/spec/fixtures/api/schemas/public_api/v4/release.json index ec3fa59cdb1..078b1c0b982 100644 --- a/spec/fixtures/api/schemas/public_api/v4/release.json +++ b/spec/fixtures/api/schemas/public_api/v4/release.json @@ -15,6 +15,7 @@ "author": { "oneOf": [{ "type": "null" }, { "$ref": "user/basic.json" }] }, + "milestone": { "type": "string" }, "assets": { "required": ["count", "links", "sources"], "properties": { diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index ec4a6ef05b9..c6aa4a2482c 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -62,6 +62,8 @@ milestone: - participants - events - boards +- milestone_release +- release snippets: - author - project @@ -72,6 +74,8 @@ releases: - author - project - links +- milestone_release +- milestone links: - release project_members: @@ -484,3 +488,6 @@ lists: - board - label - list_user_preferences +milestone_releases: +- milestone +- release diff --git a/spec/models/milestone_release_spec.rb b/spec/models/milestone_release_spec.rb new file mode 100644 index 00000000000..d6f73275977 --- /dev/null +++ b/spec/models/milestone_release_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe MilestoneRelease do + let(:project) { create(:project) } + let(:release) { create(:release, project: project) } + let(:milestone) { create(:milestone, project: project) } + + subject { build(:milestone_release, release: release, milestone: milestone) } + + describe 'associations' do + it { is_expected.to belong_to(:milestone) } + it { is_expected.to belong_to(:release) } + end + + describe 'validations' do + it { is_expected.to validate_uniqueness_of(:milestone_id).scoped_to(:release_id) } + + context 'when milestone and release do not have the same project' do + it 'is not valid' do + other_project = create(:project) + release = build(:release, project: other_project) + milestone_release = described_class.new(milestone: milestone, release: release) + expect(milestone_release).not_to be_valid + end + end + + context 'when milestone and release have the same project' do + it 'is valid' do + milestone_release = described_class.new(milestone: milestone, release: release) + expect(milestone_release).to be_valid + end + end + end +end diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 3704a2d468d..64030f5b92a 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -54,11 +54,31 @@ describe Milestone do expect(milestone.errors[:due_date]).to include("date must not be after 9999-12-31") end end + + describe 'milestone_release' do + let(:milestone) { build(:milestone, project: project) } + + context 'when it is tied to a release for another project' do + it 'creates a validation error' do + other_project = create(:project) + milestone.release = build(:release, project: other_project) + expect(milestone).not_to be_valid + end + end + + context 'when it is tied to a release for the same project' do + it 'is valid' do + milestone.release = build(:release, project: project) + expect(milestone).to be_valid + end + end + end end describe "Associations" do it { is_expected.to belong_to(:project) } it { is_expected.to have_many(:issues) } + it { is_expected.to have_one(:release) } end let(:project) { create(:project, :public) } diff --git a/spec/models/release_spec.rb b/spec/models/release_spec.rb index e9d846e7291..29ce9f762b0 100644 --- a/spec/models/release_spec.rb +++ b/spec/models/release_spec.rb @@ -13,6 +13,7 @@ RSpec.describe Release do it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:author).class_name('User') } it { is_expected.to have_many(:links).class_name('Releases::Link') } + it { is_expected.to have_one(:milestone) } end describe 'validation' do @@ -34,6 +35,20 @@ RSpec.describe Release do expect(existing_release_without_name.name).to be_nil end end + + context 'when a release is tied to a milestone for another project' do + it 'creates a validation error' do + release.milestone = build(:milestone, project: create(:project)) + expect(release).not_to be_valid + end + end + + context 'when a release is tied to a milestone linked to the same project' do + it 'is valid' do + release.milestone = build(:milestone, project: project) + expect(release).to be_valid + end + end end describe '#assets_count' do diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb index 3a22e4d4f92..ff1e1256166 100644 --- a/spec/services/milestones/destroy_service_spec.rb +++ b/spec/services/milestones/destroy_service_spec.rb @@ -65,5 +65,19 @@ describe Milestones::DestroyService do expect { service.execute(group_milestone) }.not_to change { Event.count } end end + + context 'when a release is tied to a milestone' do + it 'destroys the milestone but not the associated release' do + release = create( + :release, + tag: 'v1.0', + project: project, + milestone: milestone + ) + + expect { service.execute(milestone) }.not_to change { Release.count } + expect(release.reload).to be_persisted + end + end end end diff --git a/spec/services/releases/create_service_spec.rb b/spec/services/releases/create_service_spec.rb index e26676cdd55..5c9d6537df1 100644 --- a/spec/services/releases/create_service_spec.rb +++ b/spec/services/releases/create_service_spec.rb @@ -72,6 +72,15 @@ describe Releases::CreateService do expect(project.releases.find_by(tag: tag_name).description).to eq(description) end end + + context 'when a passed-in milestone does not exist for this project' do + it 'raises an error saying the milestone is inexistent' do + service = described_class.new(project, user, params.merge!({ milestone: 'v111.0' })) + result = service.execute + expect(result[:status]).to eq(:error) + expect(result[:message]).to eq('Milestone does not exist') + end + end end describe '#find_or_build_release' do @@ -80,5 +89,58 @@ describe Releases::CreateService do expect(project.releases.count).to eq(0) end + + context 'when existing milestone is passed in' do + let(:title) { 'v1.0' } + let(:milestone) { create(:milestone, :active, project: project, title: title) } + let(:params_with_milestone) { params.merge!({ milestone: title }) } + + it 'creates a release and ties this milestone to it' do + service = described_class.new(milestone.project, user, params_with_milestone) + result = service.execute + + expect(project.releases.count).to eq(1) + expect(result[:status]).to eq(:success) + + release = project.releases.last + + expect(release.milestone).to eq(milestone) + end + + context 'when another release was previously created with that same milestone linked' do + it 'also creates another release tied to that same milestone' do + other_release = create(:release, milestone: milestone, project: project, tag: 'v1.0') + service = described_class.new(milestone.project, user, params_with_milestone) + service.execute + release = project.releases.last + + expect(release.milestone).to eq(milestone) + expect(other_release.milestone).to eq(milestone) + expect(release.id).not_to eq(other_release.id) + end + end + end + + context 'when no milestone is passed in' do + it 'creates a release without a milestone tied to it' do + expect(params.key? :milestone).to be_falsey + service.execute + release = project.releases.last + expect(release.milestone).to be_nil + end + + it 'does not create any new MilestoneRelease object' do + expect { service.execute }.not_to change { MilestoneRelease.count } + end + end + + context 'when an empty value is passed as a milestone' do + it 'creates a release without a milestone tied to it' do + service = described_class.new(project, user, params.merge!({ milestone: '' })) + service.execute + release = project.releases.last + expect(release.milestone).to be_nil + end + end end end diff --git a/spec/services/releases/destroy_service_spec.rb b/spec/services/releases/destroy_service_spec.rb index f4c901e6585..c3172e5edbc 100644 --- a/spec/services/releases/destroy_service_spec.rb +++ b/spec/services/releases/destroy_service_spec.rb @@ -57,5 +57,15 @@ describe Releases::DestroyService do http_status: 403) end end + + context 'when a milestone is tied to the release' do + let!(:milestone) { create(:milestone, :active, project: project, title: 'v1.0') } + let!(:release) { create(:release, milestone: milestone, project: project, tag: tag) } + + it 'destroys the release but leave the milestone intact' do + expect { subject }.not_to change { Milestone.count } + expect(milestone.reload).to be_persisted + end + end end end diff --git a/spec/services/releases/update_service_spec.rb b/spec/services/releases/update_service_spec.rb index 14e6a5f13c8..944f3d8c9ad 100644 --- a/spec/services/releases/update_service_spec.rb +++ b/spec/services/releases/update_service_spec.rb @@ -48,5 +48,42 @@ describe Releases::UpdateService do it_behaves_like 'a failed update' end + + context 'when a milestone is passed in' do + let(:old_title) { 'v1.0' } + let(:new_title) { 'v2.0' } + let(:milestone) { create(:milestone, project: project, title: old_title) } + let(:new_milestone) { create(:milestone, project: project, title: new_title) } + let(:params_with_milestone) { params.merge!({ milestone: new_title }) } + + before do + release.milestone = milestone + release.save! + + described_class.new(new_milestone.project, user, params_with_milestone).execute + release.reload + end + + it 'updates the related milestone accordingly' do + expect(release.milestone.title).to eq(new_title) + end + end + + context "when an 'empty' milestone is passed in" do + let(:milestone) { create(:milestone, project: project, title: 'v1.0') } + let(:params_with_empty_milestone) { params.merge!({ milestone: '' }) } + + before do + release.milestone = milestone + release.save! + + described_class.new(milestone.project, user, params_with_empty_milestone).execute + release.reload + end + + it 'removes the old milestone and does not associate any new milestone' do + expect(release.milestone).to be_nil + end + end end end |