diff --git a/app/experiments/empty_repo_upload_experiment.rb b/app/experiments/empty_repo_upload_experiment.rb deleted file mode 100644 index c8c75f32d69c581ccba4e8209be73e3079594c3c..0000000000000000000000000000000000000000 --- a/app/experiments/empty_repo_upload_experiment.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -class EmptyRepoUploadExperiment < ApplicationExperiment - include ProjectCommitCount - - TRACKING_START_DATE = DateTime.parse('2021/4/20') - INITIAL_COMMIT_COUNT = 1 - - def track_initial_write - return unless should_track? # early return if we don't need to ask for commit counts - return unless context.project.created_at > TRACKING_START_DATE # early return for older projects - return unless commit_count == INITIAL_COMMIT_COUNT - - track(:initial_write, project: context.project) - end - - private - - def commit_count - commit_count_for(context.project, max_count: INITIAL_COMMIT_COUNT, experiment: name) - end -end diff --git a/app/experiments/force_company_trial_experiment.rb b/app/experiments/force_company_trial_experiment.rb deleted file mode 100644 index e7b98bb18ad04e43796a9f22e2c29494b2d5ada6..0000000000000000000000000000000000000000 --- a/app/experiments/force_company_trial_experiment.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -class ForceCompanyTrialExperiment < ApplicationExperiment - exclude :setup_for_personal - - private - - def setup_for_personal - !context.user.setup_for_company - end -end diff --git a/app/experiments/logged_out_marketing_header_experiment.rb b/app/experiments/logged_out_marketing_header_experiment.rb deleted file mode 100644 index 3d88d94aec402c9a0012d3fd6b04be3b00fee379..0000000000000000000000000000000000000000 --- a/app/experiments/logged_out_marketing_header_experiment.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -class LoggedOutMarketingHeaderExperiment < ApplicationExperiment - # These default behaviors are overriden in ApplicationHelper and header - # template partial - control {} - candidate {} - variant(:trial_focused) {} -end diff --git a/danger/experiments/Dangerfile b/danger/experiments/Dangerfile new file mode 100644 index 0000000000000000000000000000000000000000..3a206bc876e3f21383dedd8844534003fe4e23b1 --- /dev/null +++ b/danger/experiments/Dangerfile @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +unless experiments.class_files_removed? + msg = "This merge request removes experiment: `#{experiments.removed_experiments.join(',')}`" \ + ", please also remove the class file." + fail msg # rubocop:disable Style/SignalException +end diff --git a/danger/plugins/experiments.rb b/danger/plugins/experiments.rb new file mode 100644 index 0000000000000000000000000000000000000000..b7fd6573c306a85d4701f69727d4e157b2674d40 --- /dev/null +++ b/danger/plugins/experiments.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require_relative '../../tooling/danger/experiments' + +module Danger + class Experiments < ::Danger::Plugin + # Put the helper code somewhere it can be tested + include Tooling::Danger::Experiments + end +end diff --git a/spec/experiments/force_company_trial_experiment_spec.rb b/spec/experiments/force_company_trial_experiment_spec.rb deleted file mode 100644 index 42a3245771aab92e33a75af4bcd32da71b84d502..0000000000000000000000000000000000000000 --- a/spec/experiments/force_company_trial_experiment_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe ForceCompanyTrialExperiment, :experiment do - subject { described_class.new(current_user: user) } - - let(:user) { create(:user, setup_for_company: setup_for_company) } - let(:setup_for_company) { true } - - context 'when a user is setup_for_company' do - it 'is not excluded' do - expect(subject).not_to exclude(user: user) - end - end - - context 'when a user is not setup_for_company' do - let(:setup_for_company) { nil } - - it 'is excluded' do - expect(subject).to exclude(user: user) - end - end -end diff --git a/spec/tooling/danger/experiments_spec.rb b/spec/tooling/danger/experiments_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..85f8060a3ec4757469ad534448e7f032c7d7cc53 --- /dev/null +++ b/spec/tooling/danger/experiments_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'gitlab-dangerfiles' +require 'gitlab/dangerfiles/spec_helper' + +require_relative '../../../tooling/danger/experiments' + +RSpec.describe Tooling::Danger::Experiments, feature_category: :tooling do + include_context "with dangerfile" + + let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) } + + subject(:experiments) { fake_danger.new(helper: fake_helper) } + + describe '#removed_experiments' do + let(:removed_experiments_yml_files) do + [ + 'config/feature_flags/experiment/tier_badge.yml', + 'ee/config/feature_flags/experiment/direct_to_trial.yml' + ] + end + + let(:deleted_files) do + [ + 'app/models/model.rb', + 'app/assets/javascripts/file.js' + ] + removed_experiments_yml_files + end + + it 'returns names of removed experiments' do + expect(experiments.removed_experiments).to eq(%w[tier_badge direct_to_trial]) + end + end + + describe '#class_files_removed?' do + let(:removed_experiments_name) { current_experiment_with_class_files_example } + + context 'when yml file is deleted but not class file' do + let(:deleted_files) { ["config/feature_flags/experiment/#{removed_experiments_name}.yml"] } + + it 'returns false' do + expect(experiments.class_files_removed?).to eq(false) + end + end + + context 'when yml file is deleted but no corresponding class file exists' do + let(:deleted_files) { ["config/feature_flags/experiment/fake_experiment.yml"] } + + it 'returns true' do + expect(experiments.class_files_removed?).to eq(true) + end + end + end + + def current_experiment_with_class_files_example + path = Dir.glob("app/experiments/*.rb").last + File.basename(path).chomp('_experiment.rb') + end +end diff --git a/tooling/danger/experiments.rb b/tooling/danger/experiments.rb new file mode 100644 index 0000000000000000000000000000000000000000..49489419bab54189c2dae1cedb582df8dadfa2ad --- /dev/null +++ b/tooling/danger/experiments.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module Tooling + module Danger + module Experiments + EXPERIMENTS_YML_REGEX = %r{\A(ee/)?config/feature_flags/experiment/} + CLASS_FILES_DIR = %w[app/experiments/ ee/app/experiments/].freeze + + def class_files_removed? + (removed_experiments & current_experiments_with_class_files).empty? + end + + def removed_experiments + yml_files_paths = helper.deleted_files + + yml_files_paths.select { |path| path =~ EXPERIMENTS_YML_REGEX }.map { |path| File.basename(path).chomp('.yml') } + end + + private + + def current_experiments_with_class_files + experiment_names = [] + + CLASS_FILES_DIR.each do |directory_path| + experiment_names += Dir.glob("#{directory_path}*.rb").map do |path| + File.basename(path).chomp('_experiment.rb') + end + end + + experiment_names + end + end + end +end