Skip to content

Commit

Permalink
(PDK-1557) Detect Control Repositories
Browse files Browse the repository at this point in the history
Previously the PDK treats everything as a module.  This commit begins the work
to add Control Repo support by detecting Control Repositories and Bolt Project
directories.
  • Loading branch information
glennsarti committed Jan 15, 2020
1 parent 89917ad commit 565f88d
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/pdk.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
module PDK
autoload :Analytics, 'pdk/analytics'
autoload :AnswerFile, 'pdk/answer_file'
autoload :Bolt, 'pdk/bolt'
autoload :Config, 'pdk/config'
autoload :ControlRepo, 'pdk/control_repo'
autoload :Generate, 'pdk/generate'
autoload :Logger, 'pdk/logger'
autoload :Module, 'pdk/module'
Expand Down
19 changes: 19 additions & 0 deletions lib/pdk/bolt.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require 'pdk'

module PDK
module Bolt
# Returns true or false depending on if any of the common files and directories in
# a Bolt Project are found in the specified directory. If a directory is not specified,
# the current working directory is used.
#
# @see https://puppet.com/docs/bolt/latest/bolt_project_directories.html
#
# @return [boolean] True if any bolt specific files or directories are present
#
def bolt_project_root?(path = Dir.pwd)
return true if File.basename(path) == 'Boltdir' && PDK::Util::Filesystem.directory?(path)
PDK::Util::Filesystem.file?(File.join(path, 'bolt.yaml'))
end
module_function :bolt_project_root?
end
end
45 changes: 45 additions & 0 deletions lib/pdk/control_repo.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require 'pdk'

module PDK
module ControlRepo
CONTROL_REPO_FILES = %w[environment.conf Puppetfile].freeze

# Returns path to the root of the Control Repo being worked on.
#
# An environment.conf is required for a Control Repo, whereas Puppetfile is
# optional. Note that a Bolt Project can also be a Control Repo.
#
# @see https://puppet.com/docs/pe/latest/control_repo.html
#
# @param strict_check [Boolean] When strict_check is true, only return the path
# if the Control Repo is strictly _only_ a control repository. For example,
# not also a Puppet Bolt project directory Default is false.
#
# @return [String, nil] Fully qualified base path to Control Repo, or nil if
# the current working dir does not appear to be within a Control Repo.
def find_control_repo_root(strict_check = false)
environment_conf_path = PDK::Util.find_upwards('environment.conf')
path = if environment_conf_path
File.dirname(environment_conf_path)
elsif control_repo_root?(Dir.pwd)
Dir.pwd
else
nil
end
return path if path.nil? || !strict_check
PDK::Bolt.bolt_project_root?(path) ? nil : path
end
module_function :find_control_repo_root

# Returns true or false depending on if any of the common files in a Control Repo
# are found in the specified directory. If a directory is not specified, the current
# working directory is used.
#
# @return [boolean] True if any folders from CONTROL_REPO_FILES are found in the current dir,
# false otherwise.
def control_repo_root?(path = Dir.pwd)
CONTROL_REPO_FILES.any? { |file| PDK::Util::Filesystem.file?(File.join(path, file)) }
end
module_function :control_repo_root?
end
end
63 changes: 63 additions & 0 deletions spec/unit/pdk/bolt_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
require 'spec_helper'
require 'pdk/util'

describe PDK::Bolt do
describe '.bolt_project_root?' do
# We use NUL here because that should never be a valid directory name. But it will work with RSpec mocking.
let(:test_path) { '\x00path/test' }

before(:each) do
allow(PDK::Util::Filesystem).to receive(:file?).and_call_original
end

# Directories which indicate a bolt project
%w[
Boltdir
].each do |testcase|
it "detects the directory #{testcase} as being the root of a bolt project" do
path = File.join(test_path, testcase)
allow(PDK::Util::Filesystem).to receive(:directory?).with(path).and_return(true)
expect(described_class.bolt_project_root?(path)).to eq(true)
end
end

# Directories which do not indicate a bolt project
%w[
boltdir
Boltdir/something
].each do |testcase|
it "detects the directory #{testcase} as not being the root of a bolt project" do
path = File.join(test_path, testcase)
allow(PDK::Util::Filesystem).to receive(:directory?).with(path).and_return(true)
expect(described_class.bolt_project_root?(path)).to eq(false)
end
end

# Files which indicate a bolt project
%w[
bolt.yaml
].each do |testcase|
it "detects ./#{testcase} as being in the root of a bolt project" do
allow(PDK::Util::Filesystem).to receive(:file?).with(File.join(test_path, testcase)).and_return(true)
expect(described_class.bolt_project_root?(test_path)).to eq(true)
end
end

# Files which do not indicate a bolt project
%w[
Puppetfile
environment.conf
metadata.json
].each do |testcase|
it "detects ./#{testcase} as not being in the root of a bolt project" do
allow(PDK::Util::Filesystem).to receive(:file?).with(File.join(test_path, testcase)).and_return(true)
expect(described_class.bolt_project_root?(test_path)).to eq(false)
end
end

it 'uses the current directory if a directory is not specified' do
expect(PDK::Util::Filesystem).to receive(:file?) { |path| expect(path).to start_with(Dir.pwd) }.at_least(:once)
described_class.bolt_project_root?
end
end
end
120 changes: 120 additions & 0 deletions spec/unit/pdk/control_repo_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
require 'spec_helper'
require 'pdk/util'

describe PDK::ControlRepo do
RSpec.shared_examples 'a discoverable control repo' do
before(:each) do
allow(PDK::Util).to receive(:find_upwards).with('environment.conf').and_return(environment_path)
allow(described_class).to receive(:control_repo_root?).and_return(control_repo_root)
end

context 'when a environment.conf file can be found upwards' do
let(:environment_path) { '/path/to/the/repo/environment.conf' }
let(:control_repo_root) { true }

it 'returns the path to the directory containing the environment.conf file' do
is_expected.to eq(File.dirname(environment_path))
end
end

context 'when a environment.conf file could not be found but control repo files can' do
let(:environment_path) { nil }
let(:control_repo_root) { true }

it { is_expected.to eq(Dir.pwd) }
end

context 'when a environment.conf file and control repo files could not be found' do
let(:environment_path) { nil }
let(:control_repo_root) { false }

it { is_expected.to be_nil }
end
end

describe '.control_repo_root' do
context 'with strict_check set to false' do
subject { described_class.find_control_repo_root(false) }

it_behaves_like 'a discoverable control repo'
end

context 'with strict_check set to true but is not a Bolt project dir' do
subject { described_class.find_control_repo_root(true) }

before(:each) do
allow(PDK::Bolt).to receive(:bolt_project_root?).and_return(false)
end

it_behaves_like 'a discoverable control repo'
end

context 'with strict_check set to true and is also a Bolt project dir' do
subject { described_class.find_control_repo_root(true) }

before(:each) do
allow(PDK::Util).to receive(:find_upwards).with('environment.conf').and_return(environment_path)
allow(described_class).to receive(:control_repo_root?).and_return(control_repo_root)
allow(PDK::Bolt).to receive(:bolt_project_root?).and_return(true)
end

context 'when a environment.conf file can be found upwards' do
let(:environment_path) { '/path/to/the/repo/environment.conf' }
let(:control_repo_root) { true }

it { is_expected.to be_nil }
end

context 'when a environment.conf file could not be found but control repo files can' do
let(:environment_path) { nil }
let(:control_repo_root) { true }

it { is_expected.to be_nil }
end

context 'when a environment.conf file and control repo files could not be found' do
let(:environment_path) { nil }
let(:control_repo_root) { false }

it { is_expected.to be_nil }
end
end
end

describe '.control_repo_root?' do
# We use NUL here because that should never be a valid directory name. But it will work with RSpec mocking.
let(:test_path) { '\x00path/test' }

before(:each) do
allow(PDK::Util::Filesystem).to receive(:file?).and_call_original
end

# Files which indicate a control repo
%w[
Puppetfile
environment.conf
].each do |testcase|
it "detects #{testcase} as being in the root of a control repo" do
allow(PDK::Util::Filesystem).to receive(:file?).with(File.join(test_path, testcase)).and_return(true)
expect(described_class.control_repo_root?(test_path)).to eq(true)
end
end

# Files which do not indicate a control repo
%w[
puppetfile
Environment.conf
Gemfile
].each do |testcase|
it "detects #{testcase} as not being in the root of a control repo" do
allow(PDK::Util::Filesystem).to receive(:file?).with(File.join(test_path, testcase)).and_return(true)
expect(described_class.control_repo_root?(test_path)).to eq(false)
end
end

it 'uses the current directory if a directory is not specified' do
expect(PDK::Util::Filesystem).to receive(:file?) { |path| expect(path).to start_with(Dir.pwd) }.at_least(:once)
described_class.control_repo_root?
end
end
end

0 comments on commit 565f88d

Please sign in to comment.