Commit 819b3d12 authored by Adam Hegyi's avatar Adam Hegyi

Merge branch '329521-store-segment-target-groups' into 'master'

Prepare DevOps Adoption DB structure for migration

See merge request gitlab-org/gitlab!60733
parents d0ed2572 aa81c19b
---
title: Prepare devops adoption database structure for migration
merge_request: 60733
author:
type: other
# frozen_string_literal: true
class AddSnapshotNamespaceId < ActiveRecord::Migration[6.0]
def change
add_column :analytics_devops_adoption_snapshots, :namespace_id, :integer
end
end
# frozen_string_literal: true
class AddDisplayNamespaceIdToSegments < ActiveRecord::Migration[6.0]
def change
add_column :analytics_devops_adoption_segments, :display_namespace_id, :integer
end
end
# frozen_string_literal: true
class AddDevopsAdoptionIndexes < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
SEGMENTS_INDEX_NAME = 'idx_devops_adoption_segments_namespaces_pair'
SNAPSHOT_END_TIME_INDEX_NAME = 'idx_devops_adoption_segments_namespace_end_time'
SNAPSHOT_RECORDED_AT_INDEX_NAME = 'idx_devops_adoption_segments_namespace_recorded_at'
def up
add_concurrent_index :analytics_devops_adoption_snapshots, [:namespace_id, :end_time],
name: SNAPSHOT_END_TIME_INDEX_NAME
add_concurrent_index :analytics_devops_adoption_snapshots, [:namespace_id, :recorded_at],
name: SNAPSHOT_RECORDED_AT_INDEX_NAME
add_concurrent_index :analytics_devops_adoption_segments, [:display_namespace_id, :namespace_id],
unique: true, name: SEGMENTS_INDEX_NAME
add_concurrent_foreign_key :analytics_devops_adoption_snapshots, :namespaces, column: :namespace_id
add_concurrent_foreign_key :analytics_devops_adoption_segments, :namespaces, column: :display_namespace_id
end
def down
remove_foreign_key :analytics_devops_adoption_segments, :namespaces, column: :display_namespace_id
remove_foreign_key :analytics_devops_adoption_snapshots, :namespaces, column: :namespace_id
remove_concurrent_index_by_name :analytics_devops_adoption_segments, SEGMENTS_INDEX_NAME
remove_concurrent_index_by_name :analytics_devops_adoption_snapshots, SNAPSHOT_RECORDED_AT_INDEX_NAME
remove_concurrent_index_by_name :analytics_devops_adoption_snapshots, SNAPSHOT_END_TIME_INDEX_NAME
end
end
# frozen_string_literal: true
class RemoveObsoleteSegmentsField < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
def up
with_lock_retries do
remove_column :analytics_devops_adoption_segments, :name
end
end
def down
add_column :analytics_devops_adoption_segments, :name, :text
add_text_limit :analytics_devops_adoption_segments, :name, 255
end
end
# frozen_string_literal: true
class CopyAdoptionSnapshotNamespace < ActiveRecord::Migration[6.0]
def up
execute <<-SQL
UPDATE analytics_devops_adoption_snapshots snapshots
SET namespace_id = segments.namespace_id
FROM analytics_devops_adoption_segments segments
WHERE snapshots.namespace_id IS NULL AND segments.id = snapshots.segment_id
SQL
end
def down
execute 'UPDATE analytics_devops_adoption_snapshots SET namespace_id = NULL'
end
end
# frozen_string_literal: true
class CopyAdoptionSegmentsNamespace < ActiveRecord::Migration[6.0]
def up
execute <<-SQL
UPDATE analytics_devops_adoption_segments SET display_namespace_id = namespace_id
WHERE display_namespace_id IS NULL
SQL
end
def down
execute 'UPDATE analytics_devops_adoption_segments SET display_namespace_id = NULL'
end
end
476dc70eae87ad3ee30e6be8c1afb4a2aec23a09b96daba2afbd9c4e2edb12b9
\ No newline at end of file
ebdeb56647f3a7ff5620141833c90b796a9ddfed39234bcf8063ca5b3df6c1f3
\ No newline at end of file
7f6862205e8c315da8433083fc5391f8889951f62d466e0048063322a46f9cc7
\ No newline at end of file
c4a4b214f15a1a8d7f6832782d50077189281ca9a9b1b746a0a3bc3af4a47e3c
\ No newline at end of file
77e2b8c1c6054a80122f97dda1e843149fefb7bf6694fdfa897d691d61162d81
\ No newline at end of file
c5fe6f74822168599ad5069bb7c793ec96a4bba99d15ad29cb161ef24291b56d
\ No newline at end of file
......@@ -9103,12 +9103,11 @@ ALTER SEQUENCE analytics_devops_adoption_segment_selections_id_seq OWNED BY anal
CREATE TABLE analytics_devops_adoption_segments (
id bigint NOT NULL,
name text,
last_recorded_at timestamp with time zone,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
namespace_id integer,
CONSTRAINT check_4be7a006fd CHECK ((char_length(name) <= 255))
display_namespace_id integer
);
CREATE SEQUENCE analytics_devops_adoption_segments_id_seq
......@@ -9133,7 +9132,8 @@ CREATE TABLE analytics_devops_adoption_snapshots (
security_scan_succeeded boolean NOT NULL,
end_time timestamp with time zone NOT NULL,
total_projects_count integer,
code_owners_used_count integer
code_owners_used_count integer,
namespace_id integer
);
CREATE SEQUENCE analytics_devops_adoption_snapshots_id_seq
......@@ -22133,6 +22133,12 @@ CREATE INDEX idx_container_repositories_on_exp_cleanup_status_and_start_date ON
CREATE INDEX idx_deployment_clusters_on_cluster_id_and_kubernetes_namespace ON deployment_clusters USING btree (cluster_id, kubernetes_namespace);
CREATE INDEX idx_devops_adoption_segments_namespace_end_time ON analytics_devops_adoption_snapshots USING btree (namespace_id, end_time);
CREATE INDEX idx_devops_adoption_segments_namespace_recorded_at ON analytics_devops_adoption_snapshots USING btree (namespace_id, recorded_at);
CREATE UNIQUE INDEX idx_devops_adoption_segments_namespaces_pair ON analytics_devops_adoption_segments USING btree (display_namespace_id, namespace_id);
CREATE INDEX idx_eaprpb_external_approval_rule_id ON external_approval_rules_protected_branches USING btree (external_approval_rule_id);
CREATE INDEX idx_elastic_reindexing_slices_on_elastic_reindexing_subtask_id ON elastic_reindexing_slices USING btree (elastic_reindexing_subtask_id);
......@@ -25224,6 +25230,9 @@ ALTER TABLE ONLY project_features
ALTER TABLE ONLY ci_pipelines
ADD CONSTRAINT fk_190998ef09 FOREIGN KEY (external_pull_request_id) REFERENCES external_pull_requests(id) ON DELETE SET NULL;
ALTER TABLE ONLY analytics_devops_adoption_segments
ADD CONSTRAINT fk_190a24754d FOREIGN KEY (display_namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY user_details
ADD CONSTRAINT fk_190e4fcc88 FOREIGN KEY (provisioned_by_group_id) REFERENCES namespaces(id) ON DELETE SET NULL;
......@@ -25440,6 +25449,9 @@ ALTER TABLE ONLY users
ALTER TABLE ONLY geo_event_log
ADD CONSTRAINT fk_78a6492f68 FOREIGN KEY (repository_updated_event_id) REFERENCES geo_repository_updated_events(id) ON DELETE CASCADE;
ALTER TABLE ONLY analytics_devops_adoption_snapshots
ADD CONSTRAINT fk_78c9eac821 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY lists
ADD CONSTRAINT fk_7a5553d60f FOREIGN KEY (label_id) REFERENCES labels(id) ON DELETE CASCADE;
......@@ -4,14 +4,19 @@ class Analytics::DevopsAdoption::Segment < ApplicationRecord
include IgnorableColumns
belongs_to :namespace
belongs_to :display_namespace, class_name: 'Namespace', optional: true
has_many :snapshots, inverse_of: :segment
has_one :latest_snapshot, -> { order(recorded_at: :desc) }, inverse_of: :segment, class_name: 'Snapshot'
ignore_column :name, remove_with: '13.11', remove_after: '2021-03-22'
ignore_column :name, remove_with: '14.0', remove_after: '2021-05-22'
validates :namespace, uniqueness: true, presence: true
scope :ordered_by_name, -> { includes(:namespace).order('"namespaces"."name" ASC') }
scope :for_namespaces, -> (namespaces) { where(namespace_id: namespaces) }
scope :for_parent, -> (namespace) { for_namespaces(namespace.self_and_descendants) }
# Remove in %14.0 with https://gitlab.com/gitlab-org/gitlab/-/issues/329521
before_validation -> { self.display_namespace = namespace }
end
......@@ -2,6 +2,7 @@
class Analytics::DevopsAdoption::Snapshot < ApplicationRecord
belongs_to :segment, inverse_of: :snapshots
belongs_to :namespace, optional: true
validates :segment, presence: true
validates :recorded_at, presence: true
......@@ -29,6 +30,9 @@ class Analytics::DevopsAdoption::Snapshot < ApplicationRecord
scope :for_month, -> (month_date) { where(end_time: month_date.end_of_month) }
scope :not_finalized, -> { where(arel_table[:recorded_at].lteq(arel_table[:end_time])) }
# Remove in %14.0 with https://gitlab.com/gitlab-org/gitlab/-/issues/329521
before_save -> { self.namespace = segment.namespace }
def start_time
end_time.beginning_of_month
end
......
......@@ -17,6 +17,16 @@ RSpec.describe Analytics::DevopsAdoption::Segment, type: :model do
it { is_expected.to validate_uniqueness_of(:namespace) }
end
describe '#display_namespace' do
subject { build(:devops_adoption_segment) }
it 'fills display_namespace with namespace on save' do
expect do
subject.save!
end.to change { subject.display_namespace }.to(subject.namespace)
end
end
describe '.ordered_by_name' do
subject(:segments) { described_class.ordered_by_name }
......
......@@ -57,4 +57,14 @@ RSpec.describe Analytics::DevopsAdoption::Snapshot, type: :model do
expect(segment.start_time).to eq(expected_start_time)
end
end
describe '#namespace' do
subject { build(:devops_adoption_snapshot) }
it 'fills namespace with segments namespace on save' do
expect do
subject.save!
end.to change { subject.namespace }.to(subject.segment.namespace)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20210430134202_copy_adoption_snapshot_namespace.rb')
RSpec.describe CopyAdoptionSnapshotNamespace, :migration do
let(:namespaces_table) { table(:namespaces) }
let(:segments_table) { table(:analytics_devops_adoption_segments) }
let(:snapshots_table) { table(:analytics_devops_adoption_snapshots) }
before do
namespaces_table.create!(id: 123, name: 'group1', path: 'group1')
namespaces_table.create!(id: 124, name: 'group2', path: 'group2')
segments_table.create!(id: 1, namespace_id: 123)
segments_table.create!(id: 2, namespace_id: 124)
create_snapshot(id: 1, segment_id: 1)
create_snapshot(id: 2, segment_id: 2)
create_snapshot(id: 3, segment_id: 2, namespace_id: 123)
end
it 'updates all snapshots without namespace set' do
migrate!
expect(snapshots_table.find(1).namespace_id).to eq 123
expect(snapshots_table.find(2).namespace_id).to eq 124
expect(snapshots_table.find(3).namespace_id).to eq 123
end
def create_snapshot(**additional_params)
defaults = {
recorded_at: Time.zone.now,
issue_opened: true,
merge_request_opened: true,
merge_request_approved: true,
runner_configured: true,
pipeline_succeeded: true,
deploy_succeeded: true,
security_scan_succeeded: true,
end_time: Time.zone.now.end_of_month
}
snapshots_table.create!(defaults.merge(additional_params))
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20210430135954_copy_adoption_segments_namespace.rb')
RSpec.describe CopyAdoptionSegmentsNamespace, :migration do
let(:namespaces_table) { table(:namespaces) }
let(:segments_table) { table(:analytics_devops_adoption_segments) }
before do
namespaces_table.create!(id: 123, name: 'group1', path: 'group1')
namespaces_table.create!(id: 124, name: 'group2', path: 'group2')
segments_table.create!(id: 1, namespace_id: 123, display_namespace_id: nil)
segments_table.create!(id: 2, namespace_id: 124, display_namespace_id: 123)
end
it 'updates all segments without display namespace' do
migrate!
expect(segments_table.find(1).display_namespace_id).to eq 123
expect(segments_table.find(2).display_namespace_id).to eq 123
end
end
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