diff --git a/danger/customer_success/Dangerfile b/danger/customer_success/Dangerfile new file mode 100644 index 0000000000000000000000000000000000000000..a9043e030a13ae045244fa61bfdc201aebddad2b --- /dev/null +++ b/danger/customer_success/Dangerfile @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +markdown(customer_success.build_message) diff --git a/danger/plugins/customer_success.rb b/danger/plugins/customer_success.rb new file mode 100644 index 0000000000000000000000000000000000000000..dad8174c311fd0cde1d03dbaf71ce4ebcf71403b --- /dev/null +++ b/danger/plugins/customer_success.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require_relative '../../tooling/danger/customer_success' + +module Danger + class CustomerSuccess < ::Danger::Plugin + include Tooling::Danger::CustomerSuccess + end +end diff --git a/spec/tooling/danger/customer_success_spec.rb b/spec/tooling/danger/customer_success_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..798905212f199e48e9b2becce6f23151e5cddff1 --- /dev/null +++ b/spec/tooling/danger/customer_success_spec.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'rspec-parameterized' +require 'gitlab-dangerfiles' +require 'gitlab/dangerfiles/spec_helper' +require_relative '../../../tooling/danger/customer_success' + +RSpec.describe Tooling::Danger::CustomerSuccess do + include_context "with dangerfile" + + let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) } + let(:customer_success) { fake_danger.new(helper: fake_helper) } + + describe 'customer success danger' do + using RSpec::Parameterized::TableSyntax + + where do + { + 'with data category changes to Ops and no Customer Success::Impact Check label' => { + modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb), + changed_lines: ['-data_category: cat1', '+data_category: operational'], + customer_labeled: false, + impacted: true, + impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml) + }, + 'with data category changes and Customer Success::Impact Check label' => { + modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml), + changed_lines: ['-data_category: cat1', '+data_category: operational'], + customer_labeled: true, + impacted: false, + impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml) + }, + 'with metric file changes and no data category changes' => { + modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml), + changed_lines: ['-product_stage: growth'], + customer_labeled: false, + impacted: false, + impacted_files: [] + }, + 'with data category changes from Ops' => { + modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb), + changed_lines: ['-data_category: operational', '+data_category: cat2'], + customer_labeled: false, + impacted: true, + impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml) + }, + 'with data category removed' => { + modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb), + changed_lines: ['-data_category: operational'], + customer_labeled: false, + impacted: true, + impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml) + }, + 'with data category added' => { + modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb), + changed_lines: ['+data_category: operational'], + customer_labeled: false, + impacted: true, + impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml) + }, + 'with data category in uppercase' => { + modified_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml app/models/user.rb), + changed_lines: ['+data_category: Operational'], + customer_labeled: false, + impacted: true, + impacted_files: %w(config/metrics/20210216182127_user_secret_detection_jobs.yml) + } + } + end + + with_them do + before do + allow(fake_helper).to receive(:modified_files).and_return(modified_files) + allow(fake_helper).to receive(:changed_lines).and_return(changed_lines) + allow(fake_helper).to receive(:has_scoped_label_with_scope?).and_return(customer_labeled) + allow(fake_helper).to receive(:markdown_list).with(impacted_files) + .and_return(impacted_files.map { |item| "* `#{item}`" }.join("\n")) + end + + it 'generates correct message' do + expect(customer_success.build_message).to match_expected_message + end + end + end + + def match_expected_message + return be_nil unless impacted + + start_with(described_class::CHANGED_SCHEMA_MESSAGE).and(include(*impacted_files)) + end +end diff --git a/tooling/danger/customer_success.rb b/tooling/danger/customer_success.rb new file mode 100644 index 0000000000000000000000000000000000000000..43bdeadd8a435341952be0f0a97e5f6f5cfc2af7 --- /dev/null +++ b/tooling/danger/customer_success.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Tooling + module Danger + module CustomerSuccess + CHANGED_SCHEMA_MESSAGE = <<~MSG + Notification to the Customer Success about changes to files with possible breaking downstream processes, add label `Customer Success::Impact Check`. + + /label ~"Customer Success::Impact Check" + + The following files require a review: + MSG + + FILE_PATH_REGEX = %r{((ee|jh)/)?config/metrics/.+\.yml}.freeze + CATEGORY_CHANGED = /data_category: operational/i.freeze + + def build_message + return unless impacted? + + CHANGED_SCHEMA_MESSAGE + helper.markdown_list(impacted_files) + end + + private + + def impacted? + !helper.has_scoped_label_with_scope?('Customer Success') && impacted_files.any? + end + + def impacted_files + @impacted_files ||= + metric_files.select do |file| + helper.changed_lines(file).any? { |change| metric_category_changed?(change) } + end.compact + end + + def metric_files + helper.modified_files.grep(FILE_PATH_REGEX) + end + + def metric_category_changed?(change) + change =~ CATEGORY_CHANGED + end + end + end +end