Commit 2a20a4f3 authored by Francisco Javier López's avatar Francisco Javier López Committed by Grzegorz Bizon
Browse files

Rename project's pipelines relation

parent b024c46c4a24
......@@ -51,7 +51,7 @@ project_tree:
- resource_label_events:
- label:
:priorities
- pipelines:
- ci_pipelines:
- notes:
- :author
- events:
......
......@@ -26,6 +26,8 @@ def restore
@project_members = @tree_hash.delete('project_members')
RelationRenameService.rename(@tree_hash)
ActiveRecord::Base.uncached do
ActiveRecord::Base.no_touching do
create_relations
......@@ -214,7 +216,7 @@ def excluded_keys_for_relation(relation)
end
def nil_iid_pipeline?(relation_key, relation_item)
relation_key == 'pipelines' && relation_item['iid'].nil?
relation_key == 'ci_pipelines' && relation_item['iid'].nil?
end
end
end
......
......@@ -34,6 +34,8 @@ def project_json_tree
project_json['project_members'] += group_members_json
RelationRenameService.add_new_associations(project_json)
project_json.to_json
end
......
......@@ -4,6 +4,7 @@ module Gitlab
module ImportExport
class RelationFactory
OVERRIDES = { snippets: :project_snippets,
ci_pipelines: 'Ci::Pipeline',
pipelines: 'Ci::Pipeline',
stages: 'Ci::Stage',
statuses: 'commit_status',
......
# frozen_string_literal: true
# This class is intended to help with relation renames within Gitlab versions
# and allow compatibility between versions.
# If you have to change one relationship name that is imported/exported,
# you should add it to the RENAMES constant indicating the old name and the
# new one.
# The behavior of these renamed relationships should be transient and it should
# only last one release until you completely remove the renaming from the list.
#
# When importing, this class will check the project hash and:
# - if only the old relationship name is found, it will rename it with the new one
# - if only the new relationship name is found, it will do nothing
# - if it finds both, it will use the new relationship data
#
# When exporting, this class will duplicate the keys in the resulting file.
# This way, if we open the file in an old version of the exporter it will work
# and also it will with the newer versions.
module Gitlab
module ImportExport
class RelationRenameService
RENAMES = {
'pipelines' => 'ci_pipelines' # Added in 11.6, remove in 11.7
}.freeze
def self.rename(tree_hash)
return unless tree_hash&.present?
RENAMES.each do |old_name, new_name|
old_entry = tree_hash.delete(old_name)
next if tree_hash[new_name]
next unless old_entry
tree_hash[new_name] = old_entry
end
end
def self.add_new_associations(tree_hash)
RENAMES.each do |old_name, new_name|
next if tree_hash.key?(old_name)
tree_hash[old_name] = tree_hash[new_name]
end
end
end
end
end
......@@ -20,7 +20,7 @@
visit pipelines_project_commit_path(project, project.commit.sha)
page.within('.table-holder') do
expect(page).to have_content project.pipelines[0].id # pipeline ids
expect(page).to have_content project.ci_pipelines[0].id # pipeline ids
end
end
end
......
......@@ -300,7 +300,7 @@
let(:pipeline) do
commit_sha = project.commit('HEAD').sha
project.pipelines.create(
project.ci_pipelines.create(
ref: 'HEAD',
sha: commit_sha,
source: :push,
......
......@@ -103,7 +103,7 @@ merge_request_diff_commits:
- merge_request_diff
merge_request_diff_files:
- merge_request_diff
pipelines:
ci_pipelines:
- project
- user
- stages
......@@ -265,7 +265,8 @@ project:
- notification_settings
- import_data
- commit_statuses
- pipelines
- ci_pipelines
- all_pipelines
- stages
- builds
- runner_projects
......
......@@ -197,9 +197,9 @@
end
it 'has the correct number of pipelines and statuses' do
expect(@project.pipelines.size).to eq(5)
expect(@project.ci_pipelines.size).to eq(5)
@project.pipelines.zip([2, 2, 2, 2, 2])
@project.ci_pipelines.zip([2, 2, 2, 2, 2])
.each do |(pipeline, expected_status_size)|
expect(pipeline.statuses.size).to eq(expected_status_size)
end
......
......@@ -119,16 +119,16 @@
end
it 'has pipeline stages' do
expect(saved_project_json.dig('pipelines', 0, 'stages')).not_to be_empty
expect(saved_project_json.dig('ci_pipelines', 0, 'stages')).not_to be_empty
end
it 'has pipeline statuses' do
expect(saved_project_json.dig('pipelines', 0, 'stages', 0, 'statuses')).not_to be_empty
expect(saved_project_json.dig('ci_pipelines', 0, 'stages', 0, 'statuses')).not_to be_empty
end
it 'has pipeline builds' do
builds_count = saved_project_json
.dig('pipelines', 0, 'stages', 0, 'statuses')
.dig('ci_pipelines', 0, 'stages', 0, 'statuses')
.count { |hash| hash['type'] == 'Ci::Build' }
expect(builds_count).to eq(1)
......@@ -142,11 +142,11 @@
end
it 'has pipeline commits' do
expect(saved_project_json['pipelines']).not_to be_empty
expect(saved_project_json['ci_pipelines']).not_to be_empty
end
it 'has ci pipeline notes' do
expect(saved_project_json['pipelines'].first['notes']).not_to be_empty
expect(saved_project_json['ci_pipelines'].first['notes']).not_to be_empty
end
it 'has labels with no associations' do
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::ImportExport::RelationRenameService do
let(:renames) do
{
'example_relation1' => 'new_example_relation1',
'example_relation2' => 'new_example_relation2'
}
end
let(:user) { create(:admin) }
let(:group) { create(:group, :nested) }
let!(:project) { create(:project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') }
let(:shared) { project.import_export_shared }
before do
stub_const("#{described_class}::RENAMES", renames)
end
context 'when importing' do
let(:project_tree_restorer) { Gitlab::ImportExport::ProjectTreeRestorer.new(user: user, shared: shared, project: project) }
let(:import_path) { 'spec/lib/gitlab/import_export' }
let(:file_content) { IO.read("#{import_path}/project.json") }
let!(:json_file) { ActiveSupport::JSON.decode(file_content) }
let(:tree_hash) { project_tree_restorer.instance_variable_get(:@tree_hash) }
before do
allow(shared).to receive(:export_path).and_return(import_path)
allow(ActiveSupport::JSON).to receive(:decode).with(file_content).and_return(json_file)
end
context 'when the file has only old relationship names' do
# Configuring the json as an old version exported file, with only
# the previous association with the old name
before do
renames.each do |old_name, _|
json_file[old_name.to_s] = []
end
end
it 'renames old relationships to the new name' do
expect(json_file.keys).to include(*renames.keys)
project_tree_restorer.restore
expect(json_file.keys).to include(*renames.values)
expect(json_file.keys).not_to include(*renames.keys)
end
end
context 'when the file has both the old and new relationships' do
# Configuring the json as the new version exported file, with both
# the old association name and the new one
before do
renames.each do |old_name, new_name|
json_file[old_name.to_s] = [1]
json_file[new_name.to_s] = [2]
end
end
it 'uses the new relationships and removes the old ones from the hash' do
expect(json_file.keys).to include(*renames.keys)
project_tree_restorer.restore
expect(json_file.keys).to include(*renames.values)
expect(json_file.values_at(*renames.values).flatten.uniq.first).to eq 2
expect(json_file.keys).not_to include(*renames.keys)
end
end
context 'when the file has only new relationship names' do
# Configuring the json as the future version exported file, with only
# the new association name
before do
renames.each do |_, new_name|
json_file[new_name.to_s] = []
end
end
it 'uses the new relationships' do
expect(json_file.keys).not_to include(*renames.keys)
project_tree_restorer.restore
expect(json_file.keys).to include(*renames.values)
end
end
end
context 'when exporting' do
let(:project_tree_saver) { Gitlab::ImportExport::ProjectTreeSaver.new(project: project, current_user: user, shared: shared) }
let(:project_tree) { project_tree_saver.send(:project_json) }
it 'adds old relationships to the exported file' do
project_tree.merge!(renames.values.map { |new_name| [new_name, []] }.to_h)
allow(project_tree_saver).to receive(:save) do |arg|
project_tree_saver.send(:project_json_tree)
end
result = project_tree_saver.save
saved_data = ActiveSupport::JSON.decode(result)
expect(saved_data.keys).to include(*(renames.keys + renames.values))
end
end
end
......@@ -33,8 +33,9 @@
describe 'associations' do
it 'has a bidirectional relationship with projects' do
expect(described_class.reflect_on_association(:project).has_inverse?).to eq(:pipelines)
expect(Project.reflect_on_association(:pipelines).has_inverse?).to eq(:project)
expect(described_class.reflect_on_association(:project).has_inverse?).to eq(:all_pipelines)
expect(Project.reflect_on_association(:all_pipelines).has_inverse?).to eq(:project)
expect(Project.reflect_on_association(:ci_pipelines).has_inverse?).to eq(:project)
end
end
......@@ -1186,7 +1187,7 @@ def create_build(name, *traits, queued_at: current, started_from: 0, **opts)
create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop')
create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline2, name: 'rubocop')
pipelines = project.pipelines.to_a
pipelines = project.ci_pipelines.to_a
pipelines.each(&:number_of_warnings)
......
......@@ -63,7 +63,7 @@
it { is_expected.to have_one(:forked_from_project).through(:fork_network_member) }
it { is_expected.to have_one(:auto_devops).class_name('ProjectAutoDevops') }
it { is_expected.to have_many(:commit_statuses) }
it { is_expected.to have_many(:pipelines) }
it { is_expected.to have_many(:ci_pipelines) }
it { is_expected.to have_many(:builds) }
it { is_expected.to have_many(:build_trace_section_names)}
it { is_expected.to have_many(:runner_projects) }
......@@ -142,6 +142,29 @@
expect(subject.boards.size).to eq 1
end
end
describe 'ci_pipelines association' do
context 'when feature flag pipeline_ci_sources_only is enabled' do
it 'returns only pipelines from ci_sources' do
stub_feature_flags(pipeline_ci_sources_only: true)
expect(Ci::Pipeline).to receive(:ci_sources).and_call_original
subject.ci_pipelines
end
end
context 'when feature flag pipeline_ci_sources_only is disabled' do
it 'returns all pipelines' do
stub_feature_flags(pipeline_ci_sources_only: false)
expect(Ci::Pipeline).not_to receive(:ci_sources).and_call_original
expect(Ci::Pipeline).to receive(:all).and_call_original.at_least(:once)
subject.ci_pipelines
end
end
end
end
describe 'modules' do
......@@ -3373,7 +3396,7 @@ def domain_variable
context 'with a ref that is not the default branch' do
it 'returns the latest successful pipeline for the given ref' do
expect(project.pipelines).to receive(:latest_successful_for).with('foo')
expect(project.ci_pipelines).to receive(:latest_successful_for).with('foo')
project.latest_successful_pipeline_for('foo')
end
......@@ -3401,7 +3424,7 @@ def domain_variable
it 'memoizes and returns the latest successful pipeline for the default branch' do
pipeline = double(:pipeline)
expect(project.pipelines).to receive(:latest_successful_for)
expect(project.ci_pipelines).to receive(:latest_successful_for)
.with(project.default_branch)
.and_return(pipeline)
.once
......
......@@ -16,8 +16,8 @@
let(:get_url) { "/projects/#{project.id}/repository/commits/#{sha}/statuses" }
context 'ci commit exists' do
let!(:master) { project.pipelines.create(source: :push, sha: commit.id, ref: 'master', protected: false) }
let!(:develop) { project.pipelines.create(source: :push, sha: commit.id, ref: 'develop', protected: false) }
let!(:master) { project.ci_pipelines.create(source: :push, sha: commit.id, ref: 'master', protected: false) }
let!(:develop) { project.ci_pipelines.create(source: :push, sha: commit.id, ref: 'develop', protected: false) }
context "reporter user" do
let(:statuses_id) { json_response.map { |status| status['id'] } }
......
......@@ -818,7 +818,7 @@ def push_params(branch_name)
end
context 'when the ref has a pipeline' do
let!(:pipeline) { project.pipelines.create(source: :push, ref: 'master', sha: commit.sha, protected: false) }
let!(:pipeline) { project.ci_pipelines.create(source: :push, ref: 'master', sha: commit.sha, protected: false) }
it 'includes a "created" status' do
get api(route, current_user)
......
......@@ -304,7 +304,7 @@ def expect_variables(variables, expected_variables)
it 'creates and returns a new pipeline' do
expect do
post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch
end.to change { project.pipelines.count }.by(1)
end.to change { project.ci_pipelines.count }.by(1)
expect(response).to have_gitlab_http_status(201)
expect(json_response).to be_a Hash
......@@ -317,8 +317,8 @@ def expect_variables(variables, expected_variables)
it 'creates and returns a new pipeline using the given variables' do
expect do
post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch, variables: variables
end.to change { project.pipelines.count }.by(1)
expect_variables(project.pipelines.last.variables, variables)
end.to change { project.ci_pipelines.count }.by(1)
expect_variables(project.ci_pipelines.last.variables, variables)
expect(response).to have_gitlab_http_status(201)
expect(json_response).to be_a Hash
......@@ -338,8 +338,8 @@ def expect_variables(variables, expected_variables)
it 'creates and returns a new pipeline using the given variables' do
expect do
post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch, variables: variables
end.to change { project.pipelines.count }.by(1)
expect_variables(project.pipelines.last.variables, variables)
end.to change { project.ci_pipelines.count }.by(1)
expect_variables(project.ci_pipelines.last.variables, variables)
expect(response).to have_gitlab_http_status(201)
expect(json_response).to be_a Hash
......@@ -353,7 +353,7 @@ def expect_variables(variables, expected_variables)
it "doesn't create a job" do
expect do
post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch
end.not_to change { project.pipelines.count }
end.not_to change { project.ci_pipelines.count }
expect(response).to have_gitlab_http_status(400)
end
......
......@@ -39,7 +39,7 @@
end
context 'Have a commit' do
let(:pipeline) { project.pipelines.last }
let(:pipeline) { project.ci_pipelines.last }
it 'creates pipeline' do
post api("/projects/#{project.id}/trigger/pipeline"), options.merge(ref: 'master')
......
......@@ -44,7 +44,7 @@ def execute_service(
expect(pipeline).to be_valid
expect(pipeline).to be_persisted
expect(pipeline).to be_push
expect(pipeline).to eq(project.pipelines.last)
expect(pipeline).to eq(project.ci_pipelines.last)
expect(pipeline).to have_attributes(user: user)
expect(pipeline).to have_attributes(status: 'pending')
expect(pipeline.repository_source?).to be true
......@@ -731,8 +731,8 @@ def previous_commit_sha_from_ref(ref)
it 'creates a merge request pipeline in the forked project' do
expect(pipeline).to be_persisted
expect(project.pipelines).to eq([pipeline])
expect(target_project.pipelines).to be_empty
expect(project.ci_pipelines).to eq([pipeline])
expect(target_project.ci_pipelines).to be_empty
end
end
......
......@@ -25,12 +25,12 @@
context 'when there is a scheduled pipeline within next_run_at' do
shared_examples 'successful scheduling' do
it 'creates a new pipeline' do
expect { subject }.to change { project.pipelines.count }.by(1)
expect { subject }.to change { project.ci_pipelines.count }.by(1)
expect(Ci::Pipeline.last).to be_schedule
pipeline_schedule.reload
expect(pipeline_schedule.next_run_at).to be > Time.now
expect(pipeline_schedule).to eq(project.pipelines.last.pipeline_schedule)
expect(pipeline_schedule).to eq(project.ci_pipelines.last.pipeline_schedule)
expect(pipeline_schedule).to be_active
end
end
......@@ -54,7 +54,7 @@
end
it 'does not creates a new pipeline' do
expect { subject }.not_to change { project.pipelines.count }
expect { subject }.not_to change { project.ci_pipelines.count }
end
end
......@@ -64,7 +64,7 @@
end
it 'creates a failed pipeline with the reason' do
expect { subject }.to change { project.pipelines.count }.by(1)
expect { subject }.to change { project.ci_pipelines.count }.by(1)
expect(Ci::Pipeline.last).to be_config_error
expect(Ci::Pipeline.last.yaml_errors).not_to be_nil
end
......@@ -105,7 +105,7 @@
end
it 'does not create a pipeline' do
expect { subject }.not_to change { project.pipelines.count }
expect { subject }.not_to change { project.ci_pipelines.count }
end
it 'does not raise an exception' do
......@@ -135,7 +135,7 @@
end
it 'does not create a pipeline' do
expect { subject }.not_to change { project.pipelines.count }
expect { subject }.not_to change { project.ci_pipelines.count }
end
it 'does not raise an exception' do
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment