diff --git a/CHANGELOG.mkd b/CHANGELOG.mkd index db8aefcd1..28212f362 100644 --- a/CHANGELOG.mkd +++ b/CHANGELOG.mkd @@ -2,6 +2,12 @@ CHANGELOG ========= Unreleased +---------- +## Changes + +(#823) Add filter_command configuration option for git repositories +(Thanks to [mhumpula](https://github.com/mhumpula) for the [feature](https://github.com/puppetlabs/r10k/pull/823/conflicts).) + ---- 3.5.2 diff --git a/doc/dynamic-environments/configuration.mkd b/doc/dynamic-environments/configuration.mkd index ab0e408ed..93b5a0972 100644 --- a/doc/dynamic-environments/configuration.mkd +++ b/doc/dynamic-environments/configuration.mkd @@ -411,6 +411,29 @@ sources: - 'dev' ``` +### filter_command + +You can filter out any branch based on the result of the command specified as +'filter_command'. Currently it only works with git repository. Non zero return +status of the command results in a branch beeing removed. The command is passed +additional environment variables + +* GIT_DIR – path to the cached git repository +* R10K_BRANCH – branch which is being filtered +* R10K_NAME – source name from r10k configuration + +This can be used for example for filtering out the branches with invalid gpg signature of their latest commit + +```yaml +--- +sources: + mysource: + basedir: '/etc/puppet/environments' + filter_command: 'git verify-commit $R10K_BRANCH 2> /dev/null' +``` + +Beware that if the production branch of manifests is filtered out, you will end up with empty environment. + Examples -------- diff --git a/lib/r10k/source/git.rb b/lib/r10k/source/git.rb index bdc89f312..adbdf17d8 100644 --- a/lib/r10k/source/git.rb +++ b/lib/r10k/source/git.rb @@ -41,6 +41,10 @@ class R10K::Source::Git < R10K::Source::Base # that will be deployed as environments. attr_reader :ignore_branch_prefixes + # @!attribute [r] filter_command + # @return [String] Command to run to filter branches + attr_reader :filter_command + # Initialize the given source. # # @param name [String] The identifier for this source. @@ -61,6 +65,7 @@ def initialize(name, basedir, options = {}) @remote = options[:remote] @invalid_branches = (options[:invalid_branches] || 'correct_and_warn') @ignore_branch_prefixes = options[:ignore_branch_prefixes] + @filter_command = options[:filter_command] @cache = R10K::Git.cache.generate(@remote) end @@ -115,7 +120,7 @@ def desired_contents environments.map {|env| env.dirname } end - def filter_branches(branches, ignore_prefixes) + def filter_branches_by_regexp(branches, ignore_prefixes) filter = Regexp.new("^#{Regexp.union(ignore_prefixes)}") branches = branches.reject do |branch| result = filter.match(branch) @@ -127,14 +132,29 @@ def filter_branches(branches, ignore_prefixes) branches end + def filter_branches_by_command(branches, command) + branches.select do |branch| + result = system({'GIT_DIR' => @cache.git_dir.to_s, 'R10K_BRANCH' => branch, 'R10K_NAME' => @name.to_s}, command) + unless result + logger.warn _("Branch `%{name}:%{branch}` filtered out by filter_command %{cmd}") % {name: @name, branch: branch, cmd: command} + end + result + end + end + private def branch_names opts = {:prefix => @prefix, :invalid => @invalid_branches, :source => @name} branches = @cache.branches if @ignore_branch_prefixes && !@ignore_branch_prefixes.empty? - branches = filter_branches(branches, @ignore_branch_prefixes) + branches = filter_branches_by_regexp(branches, @ignore_branch_prefixes) + end + + if @filter_command && !@filter_command.empty? + branches = filter_branches_by_command(branches, @filter_command) end + branches.map do |branch| R10K::Environment::Name.new(branch, opts) end diff --git a/spec/unit/source/git_spec.rb b/spec/unit/source/git_spec.rb index 194232080..d10d9d0f9 100644 --- a/spec/unit/source/git_spec.rb +++ b/spec/unit/source/git_spec.rb @@ -93,9 +93,45 @@ let(:ignore_prefixes) { ['dev', 'test'] } it "filters branches" do - expect(subject.filter_branches(branches, ignore_prefixes)).to eq(['master', 'production', 'not_dev_test_me']) + expect(subject.filter_branches_by_regexp(branches, ignore_prefixes)).to eq(['master', 'production', 'not_dev_test_me']) end end + + describe "filtering branches with command" do + let(:branches) { ['master', 'development', 'production'] } + let(:filter_command) { 'sh -c "[ $R10K_BRANCH != development ]"' } + + it "filters branches" do + expect(subject.filter_branches_by_command(branches, filter_command)).to eq(['master', 'production']) + end + end + + describe "generate_environments respects filter_command setting" do + before do + allow(subject.cache).to receive(:branches).and_return ['master', 'development', 'production'] + subject.instance_variable_set(:@filter_command, '[ $R10K_BRANCH != master ]') + end + + let(:environments) { subject.generate_environments } + + it "creates an environment for each branch not filtered by filter_command" do + expect(subject.generate_environments.size).to eq(2) + end + end + + describe "generate_environments respects filter_command setting and name" do + before do + allow(subject.cache).to receive(:branches).and_return ['master', 'development', 'production'] + subject.instance_variable_set(:@filter_command, '[ $R10K_NAME = mysource ]') + end + + let(:environments) { subject.generate_environments } + + it "creates an environment for each branch not filtered by filter_command" do + expect(subject.generate_environments.size).to eq(3) + end + end + end describe R10K::Source::Git, "handling invalid branch names" do