Repository navigation
Expand file tree
/
Copy pathRakefile
More file actions
151 lines (131 loc) · 7.04 KB
/
Copy pathRakefile
File metadata and controls
151 lines (131 loc) · 7.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
require 'rake'
require 'rake_performance'
require 'find'
require 'fileutils'
require 'bundler/setup'
require 'open3'
# Escape a value for use in a Teamcity service message.
# See https://www.jetbrains.com/help/teamcity/service-messages.html#Escaped+Values
def teamcity_escape(value)
value.to_s.gsub(/[|'\[\]\n\r]/, '|' => '||', "'" => "|'", '[' => '|[', ']' => '|]', "\n" => '|n', "\r" => '|r')
end
# Write a Teamcity service message. Does nothing when we're not running within Teamcity.
def teamcity_message(name, attributes)
return unless ENV['TEAMCITY_VERSION']
attributes = attributes.map { |key, value| "#{key}='#{teamcity_escape(value)}'" }.join(' ')
puts "##teamcity[#{name} #{attributes}]"
end
# Run `kitchen test` for a single instance, retrying it if it fails, and report it to Teamcity as a test.
# Returns true if the instance passed.
def kitchen_test_instance(instance, retries:, destroy_strategy:, color:)
teamcity_message('testStarted', name: instance, captureStandardOutput: 'true')
attempts = retries + 1
errors = ''
passing_attempt = (1..attempts).find do |attempt|
puts "Testing #{instance} (attempt #{attempt} of #{attempts})"
stderr_file = ".kitchen/#{instance}.attempt#{attempt}.stderr"
passed = false
# Use test and let kitchen handle the destroy, create, converge, setup, verify, destroy workflow
sh "kitchen test #{instance} --destroy=#{destroy_strategy} --log-level=info #{color} 2> #{stderr_file}" do |ok, _|
passed = ok
errors = IO.read(stderr_file) unless ok
end
passed
end
if passing_attempt.nil?
warn errors
# Let's show some nicer teamcity errors for quicker troubleshooting
error_lines = errors.split("\n").select { |line| line.include?('failed on instance') || line.include?('Failed to complete') }
error_lines.each { |line| teamcity_message('buildProblem', description: line) }
teamcity_message('testFailed', name: instance, message: error_lines.first || "kitchen test failed for #{instance}", details: errors)
elsif passing_attempt > 1
puts "#{instance} passed on attempt #{passing_attempt} of #{attempts}"
teamcity_message('message', text: "#{instance} failed, then passed on attempt #{passing_attempt} of #{attempts}", status: 'WARNING')
end
teamcity_message('testFinished', name: instance)
!passing_attempt.nil?
end
# always destroy the kitchen when running within Teamcity
destroy_strategy = ENV['TEAMCITY_VERSION'] ? 'always' : 'passing'
color = ENV['TEAMCITY_VERSION'] ? '--no-color' : '--color'
ENV['PUPPET_COLOR'] = '--color false' if ENV['TEAMCITY_VERSION']
rootdir = File.dirname(__FILE__)
ENV['SSL_CERT_FILE'] = "#{rootdir}/cacert.pem" unless ENV['SSL_CERT_FILE']
# Don't buffer our output, so it stays in order with the output of the commands we run
# (and Teamcity service messages wrap the right output).
$stdout.sync = true
namespace :acceptance do
task :prerequisites do
raise 'Environment variable KITCHEN_YAML should be set to either .kitchen.oldsqlservers.yml, .kitchen.sqlservers.yml or .kitchen.ssms.yml' unless ENV['KITCHEN_YAML']
case ENV['KITCHEN_YAML']
when '.kitchen.oldsqlservers.yml'
raise 'Environment variable SQLSERVER2005_ISO_URL must be set to be able to run our acceptance tests' unless ENV['SQLSERVER2005_ISO_URL']
when '.kitchen.sqlservers.yml'
raise 'Environment variable SQLSERVER2008_ISO_URL must be set to be able to run our acceptance tests' unless ENV['SQLSERVER2008_ISO_URL']
raise 'Environment variable SQLSERVER2008R2_ISO_URL must be set to be able to run our acceptance tests' unless ENV['SQLSERVER2008R2_ISO_URL']
raise 'Environment variable SQLSERVER2012_ISO_URL must be set to be able to run our acceptance tests' unless ENV['SQLSERVER2012_ISO_URL']
raise 'Environment variable SQLSERVER2014_ISO_URL must be set to be able to run our acceptance tests' unless ENV['SQLSERVER2014_ISO_URL']
raise 'Environment variable SQLSERVER2016_ISO_URL must be set to be able to run our acceptance tests' unless ENV['SQLSERVER2016_ISO_URL']
raise 'Environment variable SQLSERVER2017_ISO_URL must be set to be able to run our acceptance tests' unless ENV['SQLSERVER2017_ISO_URL']
raise 'Environment variable SQLSERVER2019_ISO_URL must be set to be able to run our acceptance tests' unless ENV['SQLSERVER2019_ISO_URL']
raise 'Environment variable SQLSERVER2022_ISO_URL must be set to be able to run our acceptance tests' unless ENV['SQLSERVER2022_ISO_URL']
end
end
desc 'Install puppet modules from Puppetfile'
task :installpuppetmodules do
sh 'bundle exec r10k puppetfile install --verbose'
end
desc 'Execute the acceptance tests'
task kitchen: [:prerequisites, :installpuppetmodules] do
# How many times to retry an instance that fails, to get past transient errors.
# Defaults to no retries outside Teamcity, as a retry destroys the failed instance you might want to debug.
retries = Integer(ENV['KITCHEN_RETRIES'] || (ENV['TEAMCITY_VERSION'] ? 1 : 0))
suitename = File.basename(ENV['KITCHEN_YAML'], '.yml').sub(/\A\.kitchen\./, '')
begin
Dir.mkdir('.kitchen') unless Dir.exist?('.kitchen')
# Test each instance on its own, so that we can retry just the ones that fail
# and report each one to Teamcity as a separate test.
output, status = Open3.capture2('kitchen list --bare')
raise "Failed to list the kitchen instances in #{ENV['KITCHEN_YAML']}" unless status.success?
instances = output.split("\n").map(&:strip).select { |line| line.match?(/\A[\w-]+\z/) }
raise "No kitchen instances found in #{ENV['KITCHEN_YAML']}" if instances.empty?
teamcity_message('testSuiteStarted', name: suitename)
failed = instances.reject do |instance|
kitchen_test_instance(instance, retries: retries, destroy_strategy: destroy_strategy, color: color)
end
teamcity_message('testSuiteFinished', name: suitename)
raise "Kitchen tests failed for: #{failed.join(', ')}" unless failed.empty?
ensure
puts "##teamcity[publishArtifacts '#{Dir.pwd}/.kitchen/logs/*.log => logs.zip']"
end
end
end
namespace :check do
namespace :manifests do
desc 'Validate syntax for all manifests'
task :syntax do
sh "puppet parser validate #{rootdir}"
end
require 'puppet-lint/tasks/puppet-lint'
Rake::Task[:lint].clear
desc 'puppet-lint all the manifests'
PuppetLint::RakeTask.new :lint do |config|
# List of checks to disable
config.disable_checks = %w(80chars trailing_whitespace 2sp_soft_tabs hard_tabs)
config.relative = true
end
end
namespace :ruby do
desc 'Validate syntax for all ruby files'
task :syntax do
Dir.glob('**/*.rb').each do |ruby_file|
sh "ruby -c #{ruby_file}"
end
Dir.glob('**/*.erb').each do |erb_file|
sh "erb -P -x -T '-' #{erb_file} | ruby -c"
end
end
end
end
task checks: ['check:manifests:syntax', 'check:manifests:lint', 'check:ruby:syntax']
task default: :checks