diff --git a/gems/gitlab-housekeeper/bin/gitlab-housekeeper b/gems/gitlab-housekeeper/bin/gitlab-housekeeper index 1ad32b6562b97c75aa345fed74e1ef33d630bf9d..e81508b859dd5068b0bdc7adbc9e92d0ff6910bb 100755 --- a/gems/gitlab-housekeeper/bin/gitlab-housekeeper +++ b/gems/gitlab-housekeeper/bin/gitlab-housekeeper @@ -20,6 +20,10 @@ OptionParser.new do |opts| options[:keeps] = k end + opts.on('--filter-identifiers some-identifier-regex,another-regex', Array, 'Skip any changes where none of the identifiers match these regexes. The identifiers is an array, so at least one element must match at least one regex.') do |filters| + options[:filter_identifiers] = filters.map { |f| Regexp.new(f) } + end + opts.on('-h', '--help', 'Prints this help') do abort opts.to_s end diff --git a/gems/gitlab-housekeeper/lib/gitlab/housekeeper/change.rb b/gems/gitlab-housekeeper/lib/gitlab/housekeeper/change.rb index 749e05317d3973747e2c3fc04585bc01da4cc730..190b83e30723544332f808df16227489a0b796a7 100644 --- a/gems/gitlab-housekeeper/lib/gitlab/housekeeper/change.rb +++ b/gems/gitlab-housekeeper/lib/gitlab/housekeeper/change.rb @@ -29,6 +29,14 @@ def commit_message MARKDOWN end + def matches_filters?(filters) + filters.all? do |filter| + identifiers.any? do |identifier| + identifier.match?(filter) + end + end + end + def valid? @identifiers && @title && @description && @changed_files end diff --git a/gems/gitlab-housekeeper/lib/gitlab/housekeeper/runner.rb b/gems/gitlab-housekeeper/lib/gitlab/housekeeper/runner.rb index 51281ee5572db4d5258c1646a889dc585f27e37e..1826dff3f7f22c2f97ad1354eaaac342a7c2ae0d 100644 --- a/gems/gitlab-housekeeper/lib/gitlab/housekeeper/runner.rb +++ b/gems/gitlab-housekeeper/lib/gitlab/housekeeper/runner.rb @@ -11,7 +11,7 @@ module Gitlab module Housekeeper class Runner - def initialize(max_mrs: 1, dry_run: false, keeps: nil) + def initialize(max_mrs: 1, dry_run: false, keeps: nil, filter_identifiers: []) @max_mrs = max_mrs @dry_run = dry_run @logger = Logger.new($stdout) @@ -22,6 +22,8 @@ def initialize(max_mrs: 1, dry_run: false, keeps: nil) else all_keeps end + + @filter_identifiers = filter_identifiers end def run @@ -39,6 +41,13 @@ def run branch_name = git.commit_in_branch(change) add_standard_change_data(change) + # Must be done after we commit so that we don't keep around changed files. We could checkout those files + # but then it might be riskier in local development in case we lose unrelated changes. + unless change.matches_filters?(@filter_identifiers) + puts "Skipping change: #{change.identifiers} due to not matching filter" + next + end + if @dry_run dry_run(change, branch_name) else diff --git a/gems/gitlab-housekeeper/spec/gitlab/housekeeper/change_spec.rb b/gems/gitlab-housekeeper/spec/gitlab/housekeeper/change_spec.rb index 8060507210085c663bdfcc25d60e050c640a4410..e1fecd6d16a37dbc4d2a012d315b5f7999dd40ed 100644 --- a/gems/gitlab-housekeeper/spec/gitlab/housekeeper/change_spec.rb +++ b/gems/gitlab-housekeeper/spec/gitlab/housekeeper/change_spec.rb @@ -51,4 +51,25 @@ end end end + + describe '#matches_filters?' do + let(:identifiers) { %w[this-is a-list of IdentifierS] } + let(:change) { create_change(identifiers: identifiers) } + + it 'matches when all regexes match at least one identifier' do + expect(change.matches_filters?([/list/, /Ide.*fier/])).to eq(true) + end + + it 'does not match when none of the regexes match' do + expect(change.matches_filters?([/nomatch/, /Ide.*fffffier/])).to eq(false) + end + + it 'does not match when only some of the regexes match' do + expect(change.matches_filters?([/nomatch/, /Ide.*fier/])).to eq(false) + end + + it 'matches an empty list of filters' do + expect(change.matches_filters?([])).to eq(true) + end + end end diff --git a/gems/gitlab-housekeeper/spec/gitlab/housekeeper/runner_spec.rb b/gems/gitlab-housekeeper/spec/gitlab/housekeeper/runner_spec.rb index a967d74db90a60dbabc2ba53912440b77027f5f8..13f58f52771a1a685d14507c50b7ea8c7dfed587 100644 --- a/gems/gitlab-housekeeper/spec/gitlab/housekeeper/runner_spec.rb +++ b/gems/gitlab-housekeeper/spec/gitlab/housekeeper/runner_spec.rb @@ -115,6 +115,39 @@ described_class.new(max_mrs: 2, keeps: [fake_keep]).run end + context 'when given filter_identifiers' do + it 'skips a change that does not match the filter_identifiers' do + # Branches get created. We allow branches to be created for filtered changes but we don't want to push them. + allow(git).to receive(:commit_in_branch).and_return("the-branch-should-not-be-pushed") + expect(git).to receive(:commit_in_branch).with(change2) + .and_return('the-identifier-for-the-second-change') + + # Branches get shown and pushed + expect(::Gitlab::Housekeeper::Shell).to receive(:execute) + .with('git', '--no-pager', 'diff', '--color=always', 'master', + 'the-identifier-for-the-second-change', '--', 'change1.txt', 'change2.txt') + expect(::Gitlab::Housekeeper::Shell).to receive(:execute) + .with('git', 'push', '-f', 'housekeeper', + 'the-identifier-for-the-second-change:the-identifier-for-the-second-change') + + # Merge requests get created + expect(gitlab_client).to receive(:create_or_update_merge_request) + .with( + change: change2, + source_project_id: '123', + source_branch: 'the-identifier-for-the-second-change', + target_branch: 'master', + target_project_id: '456', + update_title: true, + update_description: true, + update_labels: true, + update_reviewers: true + ) + + described_class.new(max_mrs: 2, keeps: [fake_keep], filter_identifiers: [/second/]).run + end + end + context 'when title, description, code has changed already' do it 'does not update the changed details' do # First change has updated code and description so should only update title