Skip to content

Commit

Permalink
Merge pull request #192 from GeoffWilliams/scanall2
Browse files Browse the repository at this point in the history
(#86) Support regex in R10K downloaded modules
  • Loading branch information
dylanratcliffe authored Dec 24, 2018
2 parents b36e5ba + 2d7dae5 commit e3ebd9b
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 154 deletions.
5 changes: 5 additions & 0 deletions features/run.feature
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ Feature: Run rspec and acceptance test suites
When I run onceover command "run spec"
Then I should not see any errors

Scenario: Using regexes to define tests
Given initialized control repo "caching"
When I run onceover command "run spec"
Then I should see message pattern "apache::params"

Scenario: Run spec tests with misspelled module in Puppetfile
Given initialized control repo "basic"
And in Puppetfile is misspelled module's name
Expand Down
14 changes: 9 additions & 5 deletions features/step_definitions/common.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,13 @@
expect(@cmd.output.match err_msg_regexp).to_not be nil
end

Then(/^I should see message pattern "([^"]*)"$/) do |err_msg_regexp|
expect(@cmd.success?).to be true
puts @cmd.output unless @cmd.output =~ Regexp.new(err_msg_regexp)
expect(@cmd.output).to match(err_msg_regexp)
puts @cmd.output.match(err_msg_regexp).to_s
Then(/^I should see message pattern "([^"]*)"$/) do |msg_regexp|
output_surround = 30
match = Regexp.new(msg_regexp).match(@cmd.output)
expect(@cmd.output).to match(msg_regexp)
if match
puts match.pre_match[-output_surround..-1] + match.to_s + match.post_match[0..output_surround]
else
puts @cmd.output
end
end
2 changes: 2 additions & 0 deletions lib/onceover/cli/run.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require 'onceover/runner'
require 'onceover/testconfig'
require 'onceover/logger'
require 'onceover/deploy'

class Onceover
class CLI
Expand Down Expand Up @@ -43,6 +44,7 @@ def self.command

run do |opts, args, cmd|
repo = Onceover::Controlrepo.new(opts)
Onceover::Deploy.new.deploy_local(repo, opts)
runner = Onceover::Runner.new(repo,Onceover::TestConfig.new(repo.onceover_yaml, opts), :spec)
runner.prepare!
runner.run_spec!
Expand Down
6 changes: 6 additions & 0 deletions lib/onceover/controlrepo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,17 @@ def profiles
end

def classes
logger.debug('scanning for classes specified in onceover.yaml')

# Get all of the possible places for puppet code and look for classes
code_dirs = self.config['modulepath']
# Remove interpolated references
code_dirs.delete_if { |dir| dir[0] == '$'}

# Include all r10k-downloaded modules to support vendored and/or separate
# role and profile classes
code_dirs << "#{@tempdir}/#{@environmentpath}/production/modules"

# Make sure that the paths are relative to the controlrepo root
code_dirs.map! do |dir|
File.expand_path(dir, @root)
Expand Down
152 changes: 152 additions & 0 deletions lib/onceover/deploy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# handle local deployments (run r10k in .onceover dir)
class Onceover
class Deploy
def deploy_local(repo = Onceover::Controlrepo.new, opts = {})
require 'onceover/controlrepo'
require 'pathname'

logger.debug 'Deploying locally (R10K)...'

skip_r10k = opts[:skip_r10k] || false
force = opts[:force] || false

if repo.tempdir == nil
repo.tempdir = Dir.mktmpdir('r10k')
else
logger.debug "Creating #{repo.tempdir}"
FileUtils.mkdir_p(repo.tempdir)
end

# We need to do the copy to a tempdir then move the tempdir to the
# destination, just in case we get a recursive copy
# TODO: Improve this to save I/O

# We might need to exclude some files
#
# if we are using bundler to install gems below the controlrepo
# we don't want two copies so exclude those
#
# If there are more situations like this we can add them to this array as
# full paths
excluded_dirs = []
excluded_dirs << Pathname.new("#{repo.root}/.onceover")
excluded_dirs << Pathname.new(ENV['GEM_HOME']) if ENV['GEM_HOME']

#
# A Local modules directory likely means that the user installed r10k folders into their local control repo
# This conflicts with the step where onceover installs r10k after copying the control repo to the temporary
# .onceover directory. The following skips copying the modules folder, to not later cause an error.
#
if File.directory?("#{repo.root}/modules")
logger.warn "Found modules directory in your controlrepo, skipping the copy of this directory. If you installed modules locally using r10k, this warning is normal, if you have created modules in a local modules directory, onceover does not support testing these files, please rename this directory to conform with Puppet best practices, as this folder will conflict with Puppet's native installation of modules."
end
excluded_dirs << Pathname.new("#{repo.root}/modules")

controlrepo_files = get_children_recursive(Pathname.new(repo.root))

# Exclude the files that should be skipped
controlrepo_files.delete_if do |path|
parents = [path]
path.ascend do |parent|
parents << parent
end
parents.any? { |x| excluded_dirs.include?(x) }
end

folders_to_copy = controlrepo_files.select { |x| x.directory? }
files_to_copy = controlrepo_files.select { |x| x.file? }

logger.debug "Creating temp dir as a staging directory for copying the controlrepo to #{repo.tempdir}"
temp_controlrepo = Dir.mktmpdir('controlrepo')

logger.debug "Creating directories under #{temp_controlrepo}"
FileUtils.mkdir_p(folders_to_copy.map { |folder| "#{temp_controlrepo}/#{(folder.relative_path_from(Pathname(repo.root))).to_s}"})

logger.debug "Copying files to #{temp_controlrepo}"
files_to_copy.each do |file|
FileUtils.cp(file,"#{temp_controlrepo}/#{(file.relative_path_from(Pathname(repo.root))).to_s}")
end

logger.debug "Writing manifest of copied controlrepo files"
require 'json'
# Create a manifest of all files that were in the original repo
manifest = controlrepo_files.map do |file|
# Make sure the paths are relative so they remain relevant when used later
file.relative_path_from(Pathname(repo.root)).to_s
end
# Write all but the first as this is the root and we don't care about that
File.write("#{temp_controlrepo}/.onceover_manifest.json",manifest[1..-1].to_json)

# When using puppetfile vs deploy with r10k, we want to respect the :control_branch
# located in the Puppetfile. To accomplish that, we use git and find the current
# branch name, then replace strings within the staged puppetfile, prior to copying.

logger.debug "Checking current working branch"
git_branch = `git rev-parse --abbrev-ref HEAD`.chomp

logger.debug "found #{git_branch} as current working branch"
puppetfile_contents = File.read("#{temp_controlrepo}/Puppetfile")

logger.debug "replacing :control_branch mentions in the Puppetfile with #{git_branch}"
new_puppetfile_contents = puppetfile_contents.gsub(/:control_branch/, "'#{git_branch}'")
File.write("#{temp_controlrepo}/Puppetfile", new_puppetfile_contents)

# Remove all files written by the laste onceover run, but not the ones
# added by r10k, because that's what we are trying to cache but we don't
# know what they are
old_manifest_path = "#{repo.tempdir}/#{repo.environmentpath}/production/.onceover_manifest.json"
if File.exist? old_manifest_path
logger.debug "Found manifest from previous run, parsing..."
old_manifest = JSON.parse(File.read(old_manifest_path))
logger.debug "Removing #{old_manifest.count} files"
old_manifest.reverse.each do |file|
FileUtils.rm_f(File.join("#{repo.tempdir}/#{repo.environmentpath}/production/",file))
end
end
FileUtils.mkdir_p("#{repo.tempdir}/#{repo.environmentpath}")

logger.debug "Copying #{temp_controlrepo} to #{repo.tempdir}/#{repo.environmentpath}/production"
FileUtils.cp_r("#{temp_controlrepo}/.", "#{repo.tempdir}/#{repo.environmentpath}/production")
FileUtils.rm_rf(temp_controlrepo)

# Pull the trigger! If it's not already been pulled
if repo.tempdir and not skip_r10k
if File.directory?(repo.tempdir)
# TODO: Change this to call out to r10k directly to do this
# Probably something like:
# R10K::Settings.global_settings.evaluate(with_overrides)
# R10K::Action::Deploy::Environment
prod_dir = "#{repo.tempdir}/#{repo.environmentpath}/production"
Dir.chdir(prod_dir) do
install_cmd = []
install_cmd << "r10k puppetfile install --verbose --color --puppetfile #{repo.puppetfile}"
install_cmd << "--force" if force
install_cmd = install_cmd.join(' ')
logger.debug "Running #{install_cmd} from #{prod_dir}"
system(install_cmd)
raise 'r10k could not install all required modules' unless $?.success?
end
else
raise "#{repo.tempdir} is not a directory"
end
end

# Return repo.tempdir for use
repo.tempdir
end

private

def get_children_recursive(pathname)
results = []
results << pathname
pathname.each_child do |child|
results << child
if child.directory?
results << get_children_recursive(child)
end
end
results.flatten
end
end
end
3 changes: 0 additions & 3 deletions lib/onceover/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ def initialize(repo, config, mode = [:spec, :acceptance])
end

def prepare!
# Deploy the control repo
@config.deploy_local(@repo, {:skip_r10k => @config.skip_r10k})

# Remove the entire spec directory to make sure we have
# all the latest tests
FileUtils.rm_rf("#{@repo.tempdir}/spec")
Expand Down
145 changes: 0 additions & 145 deletions lib/onceover/testconfig.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,137 +167,6 @@ def pre_condition
puppetcode.join("\n")
end

def deploy_local(repo = Onceover::Controlrepo.new, opts = {})
require 'onceover/controlrepo'
require 'pathname'

skip_r10k = opts[:skip_r10k] || false

if repo.tempdir == nil
repo.tempdir = Dir.mktmpdir('r10k')
else
logger.debug "Creating #{repo.tempdir}"
FileUtils.mkdir_p(repo.tempdir)
end

# We need to do the copy to a tempdir then move the tempdir to the
# destination, just in case we get a recursive copy
# TODO: Improve this to save I/O

# We might need to exclude some files
#
# if we are using bundler to install gems below the controlrepo
# we don't want two copies so exclude those
#
# If there are more situations like this we can add them to this array as
# full paths
excluded_dirs = []
excluded_dirs << Pathname.new("#{repo.root}/.onceover")
excluded_dirs << Pathname.new(ENV['GEM_HOME']) if ENV['GEM_HOME']

#
# A Local modules directory likely means that the user installed r10k folders into their local control repo
# This conflicts with the step where onceover installs r10k after copying the control repo to the temporary
# .onceover directory. The following skips copying the modules folder, to not later cause an error.
#
if File.directory?("#{repo.root}/modules")
logger.warn "Found modules directory in your controlrepo, skipping the copy of this directory. If you installed modules locally using r10k, this warning is normal, if you have created modules in a local modules directory, onceover does not support testing these files, please rename this directory to conform with Puppet best practices, as this folder will conflict with Puppet's native installation of modules."
end
excluded_dirs << Pathname.new("#{repo.root}/modules")

controlrepo_files = get_children_recursive(Pathname.new(repo.root))

# Exclude the files that should be skipped
controlrepo_files.delete_if do |path|
parents = [path]
path.ascend do |parent|
parents << parent
end
parents.any? { |x| excluded_dirs.include?(x) }
end

folders_to_copy = controlrepo_files.select { |x| x.directory? }
files_to_copy = controlrepo_files.select { |x| x.file? }

logger.debug "Creating temp dir as a staging directory for copying the controlrepo to #{repo.tempdir}"
temp_controlrepo = Dir.mktmpdir('controlrepo')

logger.debug "Creating directories under #{temp_controlrepo}"
FileUtils.mkdir_p(folders_to_copy.map { |folder| "#{temp_controlrepo}/#{(folder.relative_path_from(Pathname(repo.root))).to_s}"})

logger.debug "Copying files to #{temp_controlrepo}"
files_to_copy.each do |file|
FileUtils.cp(file,"#{temp_controlrepo}/#{(file.relative_path_from(Pathname(repo.root))).to_s}")
end

logger.debug "Writing manifest of copied controlrepo files"
require 'json'
# Create a manifest of all files that were in the original repo
manifest = controlrepo_files.map do |file|
# Make sure the paths are relative so they remain relevant when used later
file.relative_path_from(Pathname(repo.root)).to_s
end
# Write all but the first as this is the root and we don't care about that
File.write("#{temp_controlrepo}/.onceover_manifest.json",manifest[1..-1].to_json)

# When using puppetfile vs deploy with r10k, we want to respect the :control_branch
# located in the Puppetfile. To accomplish that, we use git and find the current
# branch name, then replace strings within the staged puppetfile, prior to copying.

logger.debug "Checking current working branch"
git_branch = `git rev-parse --abbrev-ref HEAD`.chomp

logger.debug "found #{git_branch} as current working branch"
puppetfile_contents = File.read("#{temp_controlrepo}/Puppetfile")

logger.debug "replacing :control_branch mentions in the Puppetfile with #{git_branch}"
new_puppetfile_contents = puppetfile_contents.gsub(/:control_branch/, "'#{git_branch}'")
File.write("#{temp_controlrepo}/Puppetfile", new_puppetfile_contents)

# Remove all files written by the laste onceover run, but not the ones
# added by r10k, because that's what we are trying to cache but we don't
# know what they are
old_manifest_path = "#{repo.tempdir}/#{repo.environmentpath}/production/.onceover_manifest.json"
if File.exist? old_manifest_path
logger.debug "Found manifest from previous run, parsing..."
old_manifest = JSON.parse(File.read(old_manifest_path))
logger.debug "Removing #{old_manifest.count} files"
old_manifest.reverse.each do |file|
FileUtils.rm_f(File.join("#{repo.tempdir}/#{repo.environmentpath}/production/",file))
end
end
FileUtils.mkdir_p("#{repo.tempdir}/#{repo.environmentpath}")

logger.debug "Copying #{temp_controlrepo} to #{repo.tempdir}/#{repo.environmentpath}/production"
FileUtils.cp_r("#{temp_controlrepo}/.", "#{repo.tempdir}/#{repo.environmentpath}/production")
FileUtils.rm_rf(temp_controlrepo)

# Pull the trigger! If it's not already been pulled
if repo.tempdir and not skip_r10k
if File.directory?(repo.tempdir)
# TODO: Change this to call out to r10k directly to do this
# Probably something like:
# R10K::Settings.global_settings.evaluate(with_overrides)
# R10K::Action::Deploy::Environment
prod_dir = "#{repo.tempdir}/#{repo.environmentpath}/production"
Dir.chdir(prod_dir) do
install_cmd = []
install_cmd << "r10k puppetfile install --verbose --color --puppetfile #{repo.puppetfile}"
install_cmd << "--force" if @force
install_cmd = install_cmd.join(' ')
logger.debug "Running #{install_cmd} from #{prod_dir}"
system(install_cmd)
raise 'r10k could not install all required modules' unless $?.success?
end
else
raise "#{repo.tempdir} is not a directory"
end
end

# Return repo.tempdir for use
repo.tempdir
end

def write_spec_test(location, test)
# Use an ERB template to write a spec test
File.write("#{location}/#{test.to_s}_spec.rb",
Expand Down Expand Up @@ -394,19 +263,5 @@ def run_filters(tests)
end
tests
end

private

def get_children_recursive(pathname)
results = []
results << pathname
pathname.each_child do |child|
results << child
if child.directory?
results << get_children_recursive(child)
end
end
results.flatten
end
end
end
Loading

0 comments on commit e3ebd9b

Please sign in to comment.