summaryrefslogtreecommitdiff
path: root/spec
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 /spec
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 'spec')
-rw-r--r--spec/factories/milestone_releases.rb14
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/release.json1
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml7
-rw-r--r--spec/models/milestone_release_spec.rb36
-rw-r--r--spec/models/milestone_spec.rb20
-rw-r--r--spec/models/release_spec.rb15
-rw-r--r--spec/services/milestones/destroy_service_spec.rb14
-rw-r--r--spec/services/releases/create_service_spec.rb62
-rw-r--r--spec/services/releases/destroy_service_spec.rb10
-rw-r--r--spec/services/releases/update_service_spec.rb37
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