From 69a7ed623fccb5fa7ad0e7bc87b0a007a411babc Mon Sep 17 00:00:00 2001
From: Manoj M J <mmj@gitlab.com>
Date: Fri, 3 Nov 2023 06:37:55 +0000
Subject: [PATCH] Add conversation starter when using `gitlab_main_clusterwide`
 schema

---
 danger/gitlab_schema_validation/Dangerfile    |   3 +
 danger/plugins/gitlab_schema_validation.rb    |   9 ++
 ...itlab_schema_validation_suggestion_spec.rb | 108 ++++++++++++++++++
 .../gitlab_schema_validation_suggestion.rb    |  35 ++++++
 4 files changed, 155 insertions(+)
 create mode 100644 danger/gitlab_schema_validation/Dangerfile
 create mode 100644 danger/plugins/gitlab_schema_validation.rb
 create mode 100644 spec/tooling/danger/gitlab_schema_validation_suggestion_spec.rb
 create mode 100644 tooling/danger/gitlab_schema_validation_suggestion.rb

diff --git a/danger/gitlab_schema_validation/Dangerfile b/danger/gitlab_schema_validation/Dangerfile
new file mode 100644
index 0000000000000..3d44ad592ae87
--- /dev/null
+++ b/danger/gitlab_schema_validation/Dangerfile
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+gitlab_schema_validation.add_suggestions_on_using_clusterwide_schema
diff --git a/danger/plugins/gitlab_schema_validation.rb b/danger/plugins/gitlab_schema_validation.rb
new file mode 100644
index 0000000000000..ca4bc1a12be36
--- /dev/null
+++ b/danger/plugins/gitlab_schema_validation.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+require_relative '../../tooling/danger/gitlab_schema_validation_suggestion'
+
+module Danger
+  class GitlabSchemaValidation < ::Danger::Plugin
+    include Tooling::Danger::GitlabSchemaValidationSuggestion
+  end
+end
diff --git a/spec/tooling/danger/gitlab_schema_validation_suggestion_spec.rb b/spec/tooling/danger/gitlab_schema_validation_suggestion_spec.rb
new file mode 100644
index 0000000000000..c83e031942344
--- /dev/null
+++ b/spec/tooling/danger/gitlab_schema_validation_suggestion_spec.rb
@@ -0,0 +1,108 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'gitlab/dangerfiles/spec_helper'
+
+require_relative '../../../tooling/danger/gitlab_schema_validation_suggestion'
+require_relative '../../../tooling/danger/project_helper'
+
+RSpec.describe Tooling::Danger::GitlabSchemaValidationSuggestion, feature_category: :cell do
+  include_context "with dangerfile"
+
+  let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
+  let(:fake_project_helper) { instance_double(Tooling::Danger::ProjectHelper) }
+  let(:filename) { 'db/docs/application_settings.yml' }
+  let(:file_lines) do
+    file_diff.map { |line| line.delete_prefix('+') }
+  end
+
+  let(:file_diff) do
+    [
+      "+---",
+      "+table_name: application_settings",
+      "+classes:",
+      "+- ApplicationSetting",
+      "+feature_categories:",
+      "+- continuous_integration",
+      "+description: GitLab application settings",
+      "+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/8589b4e137f50293952923bb07e2814257d7784d",
+      "+milestone: '7.7'",
+      "+gitlab_schema: #{schema}"
+    ]
+  end
+
+  subject(:gitlab_schema_validation) { fake_danger.new(helper: fake_helper) }
+
+  before do
+    allow(gitlab_schema_validation).to receive(:project_helper).and_return(fake_project_helper)
+    allow(gitlab_schema_validation.project_helper).to receive(:file_lines).and_return(file_lines)
+    allow(gitlab_schema_validation.helper).to receive(:changed_lines).with(filename).and_return(file_diff)
+    allow(gitlab_schema_validation.helper).to receive(:all_changed_files).and_return([filename])
+  end
+
+  shared_examples_for 'does not add a comment' do
+    it do
+      expect(gitlab_schema_validation).not_to receive(:markdown)
+
+      gitlab_schema_validation.add_suggestions_on_using_clusterwide_schema
+    end
+  end
+
+  context 'for discouraging the use of gitlab_main_clusterwide schema' do
+    let(:schema) { 'gitlab_main_clusterwide' }
+
+    context 'when the file path matches' do
+      it 'adds the comment' do
+        expected_comment = "\n#{described_class::SUGGESTION.chomp}"
+
+        expect(gitlab_schema_validation).to receive(:markdown).with(expected_comment, file: filename, line: 10)
+
+        gitlab_schema_validation.add_suggestions_on_using_clusterwide_schema
+      end
+    end
+
+    context 'when the file path does not match' do
+      let(:filename) { 'some_path/application_settings.yml' }
+
+      it_behaves_like 'does not add a comment'
+    end
+
+    context 'for EE' do
+      let(:filename) { 'ee/db/docs/application_settings.yml' }
+
+      it_behaves_like 'does not add a comment'
+    end
+
+    context 'for a deleted table' do
+      let(:filename) { 'db/docs/deleted_tables/application_settings.yml' }
+
+      it_behaves_like 'does not add a comment'
+    end
+  end
+
+  context 'on removing the gitlab_main_clusterwide schema' do
+    let(:file_diff) do
+      [
+        "+---",
+        "+table_name: application_settings",
+        "+classes:",
+        "+- ApplicationSetting",
+        "+feature_categories:",
+        "+- continuous_integration",
+        "+description: GitLab application settings",
+        "+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/8589b4e137f50293952923bb07e2814257d7784d",
+        "+milestone: '7.7'",
+        "-gitlab_schema: gitlab_main_clusterwide",
+        "+gitlab_schema: gitlab_main_cell"
+      ]
+    end
+
+    it_behaves_like 'does not add a comment'
+  end
+
+  context 'when a different schema is added' do
+    let(:schema) { 'gitlab_main' }
+
+    it_behaves_like 'does not add a comment'
+  end
+end
diff --git a/tooling/danger/gitlab_schema_validation_suggestion.rb b/tooling/danger/gitlab_schema_validation_suggestion.rb
new file mode 100644
index 0000000000000..e1f049fc73232
--- /dev/null
+++ b/tooling/danger/gitlab_schema_validation_suggestion.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require_relative 'suggestion'
+
+module Tooling
+  module Danger
+    module GitlabSchemaValidationSuggestion
+      include ::Tooling::Danger::Suggestor
+
+      MATCH = %r{gitlab_schema: gitlab_main_clusterwide}
+      REPLACEMENT = nil
+      DB_DOCS_PATH = %r{\Adb/docs/[^/]+\.ya?ml\z}
+
+      SUGGESTION = <<~MESSAGE_MARKDOWN
+        :warning: You have added `gitlab_main_clusterwide` as the schema for this table. We expect most tables to use the
+        `gitlab_main_cell` schema instead, as using the clusterwide schema can have significant scaling implications.
+
+        Please see the [guidelines on choosing gitlab schema](https://docs.gitlab.com/ee/development/database/multiple_databases.html#guidelines-on-choosing-between-gitlab_main_cell-and-gitlab_main_clusterwide-schema) for more information.
+
+        Please consult with ~"group::tenant scale" if you believe that the clusterwide schema is the best fit for this table.
+      MESSAGE_MARKDOWN
+
+      def add_suggestions_on_using_clusterwide_schema
+        helper.all_changed_files.grep(DB_DOCS_PATH).each do |filename|
+          add_suggestion(
+            filename: filename,
+            regex: MATCH,
+            replacement: REPLACEMENT,
+            comment_text: SUGGESTION
+          )
+        end
+      end
+    end
+  end
+end
-- 
GitLab