pdqtest 1.4.1 → 1.9.9beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +9 -3
- data/doc/acceptance_tests.md +100 -22
- data/doc/caching.md +5 -1
- data/doc/development.md +16 -5
- data/doc/emoji.md +20 -9
- data/doc/enabling_testing.md +15 -3
- data/doc/examples.md +25 -6
- data/doc/hiera.md +30 -11
- data/doc/installation.md +59 -8
- data/doc/pdk.md +334 -0
- data/doc/puppet_facts.md +45 -3
- data/doc/puppet_module_dependencies.md +34 -16
- data/doc/running_tests.md +35 -15
- data/doc/test_generation.md +11 -19
- data/doc/tips_and_tricks.md +17 -8
- data/doc/troubleshooting.md +19 -8
- data/doc/upgrading.md +125 -6
- data/doc/windows.md +51 -0
- data/docker_images/centos/Dockerfile +4 -3
- data/docker_images/centos/Makefile +1 -1
- data/docker_images/ubuntu/Dockerfile +3 -3
- data/docker_images/windows/Dockerfile +26 -0
- data/docker_images/windows/make.ps1 +2 -0
- data/exe/pdqtest +73 -28
- data/lib/pdqtest/core.rb +1 -1
- data/lib/pdqtest/docker.rb +143 -51
- data/lib/pdqtest/emoji.rb +33 -7
- data/lib/pdqtest/fastcheck.rb +19 -0
- data/lib/pdqtest/instance.rb +16 -15
- data/lib/pdqtest/logger.rb +35 -0
- data/lib/pdqtest/pdk.rb +98 -0
- data/lib/pdqtest/pdqtest1x.rb +115 -0
- data/lib/pdqtest/puppet.rb +277 -134
- data/lib/pdqtest/skeleton.rb +119 -39
- data/lib/pdqtest/upgrade.rb +42 -42
- data/lib/pdqtest/util.rb +82 -2
- data/lib/pdqtest/version.rb +1 -2
- data/pdqtest.gemspec +8 -13
- data/res/{skeleton → acceptance}/init.bats +0 -0
- data/res/{skeleton → acceptance}/init__before.bats +0 -0
- data/res/{skeleton → acceptance}/init__setup.sh +0 -0
- data/res/skeleton/.puppet-lint.rc +5 -0
- data/res/skeleton/{dot_travis.yml → .travis.yml} +0 -0
- data/res/skeleton/Makefile +20 -5
- data/res/skeleton/make.ps1 +66 -0
- data/res/skeleton/spec/fixtures/hiera.yaml +13 -0
- data/res/skeleton/spec/fixtures/hieradata/test.yaml +11 -0
- data/res/templates/examples_init.pp.erb +1 -1
- metadata +47 -115
- data/lib/pdqtest/lint.rb +0 -31
- data/lib/pdqtest/rspec.rb +0 -69
- data/lib/pdqtest/syntax.rb +0 -20
- data/res/skeleton/Gemfile +0 -7
- data/res/skeleton/Rakefile +0 -3
- data/res/skeleton/dot_gitignore +0 -9
- data/res/skeleton/dot_rspec +0 -2
- data/res/skeleton/hiera.yaml +0 -7
- data/res/skeleton/spec_helper.rb +0 -4
- data/res/skeleton/test.yaml +0 -3
data/lib/pdqtest/docker.rb
CHANGED
@@ -6,23 +6,101 @@ module PDQTest
|
|
6
6
|
OUT = 0
|
7
7
|
ERR = 1
|
8
8
|
STATUS = 2
|
9
|
-
|
9
|
+
REAL_CMD = 3
|
10
10
|
IMAGES = {
|
11
|
-
:DEFAULT => 'declarativesystems/pdqtest-
|
12
|
-
:UBUNTU => 'declarativesystems/pdqtest-ubuntu:2018-
|
11
|
+
:DEFAULT => 'declarativesystems/pdqtest-centos:2018-09-15-0',
|
12
|
+
:UBUNTU => 'declarativesystems/pdqtest-ubuntu:2018-09-15-0',
|
13
|
+
:WINDOWS => 'declarativesystems/pdqtest-windows:2018-09-18-0',
|
13
14
|
}
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
|
16
|
+
# volume paths are different for windows containers
|
17
|
+
# https://superuser.com/questions/1051520/docker-windows-container-how-to-mount-a-host-folder-as-data-volume-on-windows
|
18
|
+
# path for common things *inside* the container
|
19
|
+
#
|
20
|
+
# Also... bind mounting _files_ is impossible on windows in docker right now:
|
21
|
+
# * https://github.com/docker/for-win/issues/376
|
22
|
+
# * https://github.com/moby/moby/issues/30555
|
23
|
+
# * https://github.com/opctl/opctl/issues/207
|
24
|
+
# * https://docs.docker.com/engine/reference/commandline/run/#capture-container-id---cidfile
|
25
|
+
CONTAINER_PATHS = {
|
26
|
+
:windows => {
|
27
|
+
:testcase => 'C:\\testcase',
|
28
|
+
},
|
29
|
+
:linux => {
|
30
|
+
:yum_cache => "/var/cache/yum",
|
31
|
+
:testcase => '/testcase',
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
# path for common things on the *host* computer running pdqtest (vm, laptop, etc)
|
36
|
+
HOST_PATHS = {
|
37
|
+
:windows => {
|
38
|
+
},
|
39
|
+
:linux => {
|
40
|
+
:yum_cache => "#{Util::app_dir_expanded}/cache/yum",
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
# convenience lookup for container testcase dir since its used all over the
|
45
|
+
# place
|
46
|
+
def self.test_dir
|
47
|
+
CONTAINER_PATHS[Util.host_platform][:testcase]
|
22
48
|
end
|
23
49
|
|
50
|
+
# Map the testcase and any OS specific volumes we would always want, eg
|
51
|
+
# yum cache, random crap for systemd, etc
|
52
|
+
def self.supporting_volumes
|
53
|
+
pwd = Dir.pwd
|
54
|
+
platform = Util.host_platform
|
55
|
+
if Util.is_windows
|
56
|
+
# normalise output for windows
|
57
|
+
pwd = pwd.gsub(/\//, '\\')
|
58
|
+
end
|
59
|
+
test_dir = CONTAINER_PATHS[platform][:testcase]
|
60
|
+
volumes = {test_dir => {pwd => 'rw'}}
|
61
|
+
|
62
|
+
if ! Util.is_windows
|
63
|
+
volumes['/sys/fs/cgroup'] = {'/sys/fs/cgroup' => 'ro'}
|
64
|
+
volumes[CONTAINER_PATHS[platform][:yum_cache]] = {HOST_PATHS[platform][:yum_cache] => 'rw'}
|
65
|
+
end
|
66
|
+
|
67
|
+
volumes
|
68
|
+
end
|
69
|
+
|
70
|
+
|
24
71
|
def self.exec(container, cmd)
|
25
|
-
|
72
|
+
status = 0
|
73
|
+
res = []
|
74
|
+
|
75
|
+
res[OUT]=[]
|
76
|
+
res[ERR]=[]
|
77
|
+
res[STATUS]=0
|
78
|
+
res[REAL_CMD]=[]
|
79
|
+
|
80
|
+
Array(cmd).each do |c|
|
81
|
+
real_c = Util.wrap_cmd(c)
|
82
|
+
res[REAL_CMD] << real_c
|
83
|
+
$logger.debug "Executing: #{real_c}"
|
84
|
+
_res = container.exec(real_c, tty: true)
|
85
|
+
|
86
|
+
if c =~ /robocopy/
|
87
|
+
# robocopy exit codes break the status check we do later on - we have
|
88
|
+
# to manually 'fix' them here
|
89
|
+
if _res[STATUS] < 4
|
90
|
+
_res[STATUS] = 0
|
91
|
+
end
|
92
|
+
end
|
93
|
+
res[STATUS] += _res[STATUS]
|
94
|
+
res[OUT] += _res[OUT]
|
95
|
+
res[ERR] += _res[ERR]
|
96
|
+
|
97
|
+
# non zero status from something thats not puppet apply is probably an error
|
98
|
+
if _res[STATUS] != 0 && !(c =~ /pupet apply|bats/)
|
99
|
+
$logger.warn "non-zero exit status: #{_res[STATUS]} from #{real_c}: #{_res[OUT]} #{_res[ERR]}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
res
|
26
104
|
end
|
27
105
|
|
28
106
|
# detect the image to use based on metadata.json
|
@@ -50,7 +128,7 @@ module PDQTest
|
|
50
128
|
when "ubuntu"
|
51
129
|
supported_images << IMAGES[:UBUNTU]
|
52
130
|
when "windows"
|
53
|
-
|
131
|
+
supported_images << IMAGES[:WINDOWS]
|
54
132
|
else
|
55
133
|
supported_images << IMAGES[:DEFAULT]
|
56
134
|
end
|
@@ -60,10 +138,15 @@ module PDQTest
|
|
60
138
|
supported_images.uniq
|
61
139
|
end
|
62
140
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
141
|
+
|
142
|
+
def self.new_container(image_name, privileged)
|
143
|
+
|
144
|
+
if Util.is_windows
|
145
|
+
::Docker.url = "tcp://127.0.0.1:2375"
|
146
|
+
# nasty hack for https://github.com/swipely/docker-api/issues/441
|
147
|
+
::Docker.send(:remove_const, 'API_VERSION')
|
148
|
+
::Docker.const_set('API_VERSION', '1.24')
|
149
|
+
end
|
67
150
|
|
68
151
|
# security options seem required on OSX to allow SYS_ADMIN capability to
|
69
152
|
# work - without this container starts fine with no errors but the CAP is
|
@@ -76,47 +159,56 @@ module PDQTest
|
|
76
159
|
[]
|
77
160
|
end
|
78
161
|
|
79
|
-
if !
|
80
|
-
|
162
|
+
if ! Util.is_windows
|
163
|
+
if ! Dir.exists?(HOST_PATHS[Util.host_platform][:yum_cache])
|
164
|
+
FileUtils.mkdir_p(HOST_PATHS[Util.host_platform][:yum_cache])
|
165
|
+
end
|
81
166
|
end
|
82
167
|
|
83
|
-
#
|
84
|
-
|
85
|
-
|
168
|
+
#
|
169
|
+
# volumes (container -> host)
|
170
|
+
#
|
171
|
+
volumes = supporting_volumes
|
172
|
+
|
173
|
+
#
|
174
|
+
# binds (host -> container)
|
175
|
+
#
|
176
|
+
binds = Util.volumes2binds(volumes)
|
177
|
+
|
178
|
+
#
|
179
|
+
# hostconfig->tmpfs (linux)
|
180
|
+
#
|
181
|
+
if Util.is_windows
|
182
|
+
start_body = {}
|
183
|
+
if privileged
|
184
|
+
$logger.error "--privileged has no effect on windows"
|
185
|
+
end
|
186
|
+
else
|
187
|
+
start_body = {
|
188
|
+
'HostConfig' => {
|
189
|
+
'Tmpfs': {
|
190
|
+
'/run' => '',
|
191
|
+
'/run/lock' => '',
|
192
|
+
},
|
193
|
+
CapAdd: [ 'SYS_ADMIN'],
|
194
|
+
Privileged: privileged,
|
195
|
+
}
|
196
|
+
}
|
86
197
|
end
|
198
|
+
|
199
|
+
#
|
200
|
+
# container
|
201
|
+
#
|
202
|
+
|
87
203
|
container = ::Docker::Container.create(
|
88
204
|
'Image' => image_name,
|
89
|
-
'Volumes' =>
|
90
|
-
test_dir => {pwd => 'rw'},
|
91
|
-
HIERA_YAML_CONTAINER => {hiera_yaml_host => 'rw'},
|
92
|
-
HIERA_DIR => {hiera_dir => 'rw'},
|
93
|
-
'/sys/fs/cgroup' => {'/sys/fs/cgroup' => 'ro'},
|
94
|
-
YUM_CACHE_CONTAINER => {YUM_CACHE_HOST => 'rw'},
|
95
|
-
},
|
205
|
+
'Volumes' => volumes,
|
96
206
|
'HostConfig' => {
|
97
207
|
"SecurityOpt" => security_opt,
|
98
|
-
"Binds":
|
99
|
-
"/sys/fs/cgroup:/sys/fs/cgroup:ro",
|
100
|
-
"#{pwd}:#{test_dir}:rw",
|
101
|
-
"#{hiera_yaml_host}:#{HIERA_YAML_CONTAINER}:rw",
|
102
|
-
"#{hiera_dir}:#{HIERA_DIR}:rw",
|
103
|
-
"#{YUM_CACHE_HOST}:#{YUM_CACHE_CONTAINER}:rw",
|
104
|
-
],
|
208
|
+
"Binds": binds,
|
105
209
|
},
|
106
210
|
)
|
107
|
-
container.start(
|
108
|
-
{
|
109
|
-
#'Binds' => [ pwd +':'+ test_dir,],
|
110
|
-
'HostConfig' => {
|
111
|
-
'Tmpfs': {
|
112
|
-
'/run' => '',
|
113
|
-
'/run/lock' => '',
|
114
|
-
},
|
115
|
-
CapAdd: [ 'SYS_ADMIN'],
|
116
|
-
Privileged: privileged,
|
117
|
-
},
|
118
|
-
}
|
119
|
-
)
|
211
|
+
container.start(start_body)
|
120
212
|
|
121
213
|
container
|
122
214
|
end
|
@@ -149,7 +241,7 @@ module PDQTest
|
|
149
241
|
exec_out(res).each { |l|
|
150
242
|
# Output comes back as an array and needs to be iterated or we lose our
|
151
243
|
# ansi formatting
|
152
|
-
|
244
|
+
$logger.info l.chomp
|
153
245
|
}
|
154
246
|
end
|
155
247
|
|
@@ -162,7 +254,7 @@ module PDQTest
|
|
162
254
|
exec_err(res).each { |l|
|
163
255
|
# Output comes back as an array and needs to be iterated or we lose our
|
164
256
|
# ansi formatting
|
165
|
-
|
257
|
+
$logger.error l.chomp
|
166
258
|
}
|
167
259
|
end
|
168
260
|
|
data/lib/pdqtest/emoji.rb
CHANGED
@@ -1,17 +1,43 @@
|
|
1
1
|
module PDQTest
|
2
2
|
module Emoji
|
3
|
+
|
4
|
+
# windows can only output emojii characters in powershell ISE *but* ISE
|
5
|
+
# causes PDK to crash, so we need special lame emoji's for our windows users
|
6
|
+
EMOJIS = {
|
7
|
+
:windows => {
|
8
|
+
:pass => ":-)",
|
9
|
+
:fail => "●~*",
|
10
|
+
:overall_pass => "=D",
|
11
|
+
:overall_fail => "><(((*>",
|
12
|
+
:slow => "(-_-)zzz",
|
13
|
+
:shame => "(-_-)",
|
14
|
+
},
|
15
|
+
:linux => {
|
16
|
+
:pass => "😬",
|
17
|
+
:fail => "💣",
|
18
|
+
:overall_pass => "😎",
|
19
|
+
:overall_fail => "💩",
|
20
|
+
:slow => "🐌",
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
|
3
25
|
@@disable = false
|
4
26
|
|
5
27
|
def self.disable(disable)
|
6
28
|
@@disable = disable
|
7
29
|
end
|
8
30
|
|
31
|
+
def self.emoji(key)
|
32
|
+
EMOJIS[Util.host_platform][key] || raise("missing emoji #{key}")
|
33
|
+
end
|
34
|
+
|
9
35
|
# Print a message prefixed with optional emoji to the STDOUT logger
|
10
|
-
def self.emoji_message(
|
36
|
+
def self.emoji_message(key, message, level=::Logger::INFO)
|
11
37
|
if ! @@disable
|
12
|
-
message = "#{message} #{emoji}"
|
38
|
+
message = "#{message} #{emoji(key)}"
|
13
39
|
end
|
14
|
-
|
40
|
+
$logger.add(level) { message }
|
15
41
|
end
|
16
42
|
|
17
43
|
# print cool emoji based on status
|
@@ -20,22 +46,22 @@ module PDQTest
|
|
20
46
|
if ! @@disable
|
21
47
|
if status
|
22
48
|
# cool bananas
|
23
|
-
|
49
|
+
$logger.info lable_string + emoji_pass
|
24
50
|
else
|
25
51
|
# boom! crappy code
|
26
|
-
|
52
|
+
$logger.error lable_string + emoji_fail
|
27
53
|
end
|
28
54
|
end
|
29
55
|
end
|
30
56
|
|
31
57
|
# partial status when lots to do
|
32
58
|
def self.partial_status(status, label)
|
33
|
-
emoji_status(status,
|
59
|
+
emoji_status(status, emoji(:pass), emoji(:fail), label)
|
34
60
|
end
|
35
61
|
|
36
62
|
# Overall program exit status
|
37
63
|
def self.final_status(status)
|
38
|
-
emoji_status(status,
|
64
|
+
emoji_status(status, emoji(:overall_pass), emoji(:overall_fail), 'Overall')
|
39
65
|
end
|
40
66
|
end
|
41
67
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'pdqtest/emoji'
|
2
|
+
module PDQTest
|
3
|
+
|
4
|
+
# Faster version of syntax and lint checks
|
5
|
+
module Fastcheck
|
6
|
+
|
7
|
+
def self.run
|
8
|
+
status = system("bundle exec puppet-lint manifests")
|
9
|
+
|
10
|
+
if status
|
11
|
+
status = system("bundle exec rake syntax")
|
12
|
+
end
|
13
|
+
|
14
|
+
PDQTest::Emoji.partial_status(status, "fastcheck (syntax+lint)")
|
15
|
+
status
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/pdqtest/instance.rb
CHANGED
@@ -5,7 +5,6 @@ require 'escort'
|
|
5
5
|
|
6
6
|
module PDQTest
|
7
7
|
module Instance
|
8
|
-
TEST_DIR='/testcase'
|
9
8
|
@@keep_container = false
|
10
9
|
@@active_container = nil
|
11
10
|
@@image_name = false
|
@@ -50,29 +49,29 @@ module PDQTest
|
|
50
49
|
@@active_container = nil
|
51
50
|
|
52
51
|
if PDQTest::Puppet::find_examples().empty?
|
53
|
-
|
52
|
+
$logger.info "No acceptance tests found, annotate examples with #{PDQTest::Puppet.setting(:magic_marker)} to make some"
|
54
53
|
else
|
55
54
|
# process each supported OS
|
56
55
|
test_platforms = @@image_name || Docker::acceptance_test_images
|
57
|
-
|
56
|
+
$logger.info "Acceptance test on #{test_platforms}..."
|
58
57
|
test_platforms.each { |image_name|
|
59
|
-
|
60
|
-
@@active_container = PDQTest::Docker::new_container(
|
61
|
-
|
58
|
+
$logger.info "--- start test with #{image_name} ---"
|
59
|
+
@@active_container = PDQTest::Docker::new_container(image_name, @@privileged)
|
60
|
+
$logger.info "alive, running tests"
|
62
61
|
status &= PDQTest::Puppet.run(@@active_container, example)
|
63
62
|
|
64
63
|
if @@keep_container
|
65
|
-
|
66
|
-
|
64
|
+
$logger.info "finished build, container #{@@active_container.id} left on system"
|
65
|
+
$logger.info " docker exec -ti #{@@active_container.id} #{Util.shell} "
|
67
66
|
else
|
68
67
|
PDQTest::Docker.cleanup_container(@@active_container)
|
69
68
|
@@active_container = nil
|
70
69
|
end
|
71
70
|
|
72
|
-
|
71
|
+
$logger.info "--- end test with #{image_name} (status: #{status})---"
|
73
72
|
}
|
74
73
|
end
|
75
|
-
|
74
|
+
$logger.info "overall acceptance test status=#{status}"
|
76
75
|
status
|
77
76
|
end
|
78
77
|
|
@@ -80,8 +79,10 @@ module PDQTest
|
|
80
79
|
# pick the first test platform to test on as our shell - want to do a specific one
|
81
80
|
# just list it with --image-name
|
82
81
|
image_name = (@@image_name || Docker::acceptance_test_images).first
|
83
|
-
|
84
|
-
@@active_container = PDQTest::Docker::new_container(
|
82
|
+
$logger.info "Opening a shell in #{image_name}"
|
83
|
+
@@active_container = PDQTest::Docker::new_container(image_name, @@privileged)
|
84
|
+
|
85
|
+
PDQTest::Docker.exec(@@active_container, PDQTest::Puppet.setup)
|
85
86
|
|
86
87
|
# In theory I should be able to get something like the code below to
|
87
88
|
# redirect all input streams and give a makeshift interactive shell, howeve
|
@@ -93,10 +94,10 @@ module PDQTest
|
|
93
94
|
# puts out
|
94
95
|
# puts err
|
95
96
|
# }
|
96
|
-
system("docker exec -ti #{@@active_container.id}
|
97
|
+
system("docker exec -ti #{@@active_container.id} #{Util.shell}")
|
97
98
|
if @@keep_container
|
98
|
-
|
99
|
-
|
99
|
+
$logger.info "finished build, container #{@@active_container.id} left on system"
|
100
|
+
$logger.info " docker exec -ti #{@@active_container.id} #{Util.shell} "
|
100
101
|
else
|
101
102
|
PDQTest::Docker.cleanup_container(@@active_container)
|
102
103
|
@@active_container = nil
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'logging'
|
2
|
+
|
3
|
+
# Fixme - this should be in escort...
|
4
|
+
# credit: Dylan Ratcliffe
|
5
|
+
module PDQTest
|
6
|
+
module Logger
|
7
|
+
def self.logger
|
8
|
+
if ! $logger
|
9
|
+
# here we setup a color scheme called 'bright'
|
10
|
+
Logging.color_scheme('bright',
|
11
|
+
:lines => {
|
12
|
+
:debug => :blue,
|
13
|
+
:info => :white,
|
14
|
+
:warn => :yellow,
|
15
|
+
:error => :red,
|
16
|
+
:fatal => [:white, :on_red]
|
17
|
+
}
|
18
|
+
)
|
19
|
+
|
20
|
+
Logging.appenders.stdout(
|
21
|
+
'stdout',
|
22
|
+
:layout => Logging.layouts.pattern(
|
23
|
+
:pattern => '%m\n',
|
24
|
+
:color_scheme => 'bright'
|
25
|
+
)
|
26
|
+
)
|
27
|
+
|
28
|
+
$logger = Logging.logger['Colors']
|
29
|
+
$logger.add_appenders 'stdout'
|
30
|
+
$logger.level = :info
|
31
|
+
end
|
32
|
+
$logger
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/pdqtest/pdk.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'pdqtest/emoji'
|
2
|
+
require 'pdqtest/puppet'
|
3
|
+
require 'deep_merge'
|
4
|
+
|
5
|
+
module PDQTest
|
6
|
+
# the main purpose of this is to add emoji after running a PDK lifecycle..
|
7
|
+
# There is basically no other way to do this mega-hack. while `pdk` itself is
|
8
|
+
# a kind of selective wrapper around ruby, I couldn't get calling `pdk` from
|
9
|
+
# inside `pdk bundle` to work, nor could I figure out how to load the PDK
|
10
|
+
# libraries from the "inside"
|
11
|
+
module Pdk
|
12
|
+
SYNC_YML = '.sync.yaml'
|
13
|
+
|
14
|
+
# Copy these values from PDK generated metadata to module metadata
|
15
|
+
PDK_TAGS = [
|
16
|
+
"pdk-version",
|
17
|
+
"template-url",
|
18
|
+
"template-ref",
|
19
|
+
]
|
20
|
+
|
21
|
+
# Golden metadata key which proves PDK is already installed
|
22
|
+
PDK_VERSION_TAG = "pdk-version"
|
23
|
+
|
24
|
+
def self.run(subcommand)
|
25
|
+
if Util.is_windows
|
26
|
+
pdk = "powershell -command \"pdk #{subcommand}\" ; exit $LastExitCode"
|
27
|
+
else
|
28
|
+
pdk = "pdk #{subcommand}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# write a .fixtures.yml for PDK test commands
|
32
|
+
if subcommand =~ /test/
|
33
|
+
PDQTest::Puppet.fixtures_yml
|
34
|
+
end
|
35
|
+
|
36
|
+
# on windows our environment is heavly contaminated by bundler - we have
|
37
|
+
# to remove it's environment or pdk command will flatout refuse to run
|
38
|
+
# probably doens't hurt to do this on linux too.
|
39
|
+
env = ENV.reject { |e|
|
40
|
+
[
|
41
|
+
"BUNDLER_ORIG_BUNDLER_ORIG_MANPATH",
|
42
|
+
"BUNDLER_ORIG_BUNDLER_VERSION",
|
43
|
+
"BUNDLER_ORIG_BUNDLE_BIN_PATH",
|
44
|
+
"BUNDLER_ORIG_BUNDLE_GEMFILE",
|
45
|
+
"BUNDLER_ORIG_GEM_HOME",
|
46
|
+
"BUNDLER_ORIG_GEM_PATH",
|
47
|
+
"BUNDLER_ORIG_MANPATH",
|
48
|
+
"BUNDLER_ORIG_PATH",
|
49
|
+
"BUNDLER_ORIG_RB_USER_INSTALL",
|
50
|
+
"BUNDLER_ORIG_RUBYLIB",
|
51
|
+
"BUNDLER_ORIG_RUBYOPT",
|
52
|
+
"BUNDLER_VERSION",
|
53
|
+
"BUNDLE_BIN_PATH",
|
54
|
+
"BUNDLE_GEMFILE",
|
55
|
+
"GEM_HOME",
|
56
|
+
"GEM_PATH",
|
57
|
+
"MANPATH",
|
58
|
+
"PROMPT",
|
59
|
+
"RUBYLIB",
|
60
|
+
"RUBYOPT",
|
61
|
+
].include? e
|
62
|
+
}
|
63
|
+
|
64
|
+
status = system(env, pdk, :unsetenv_others=>true)
|
65
|
+
|
66
|
+
PDQTest::Emoji.partial_status(status, subcommand)
|
67
|
+
status
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.enable_pdk(pdk_metadata)
|
71
|
+
if ! is_pdk_enabled
|
72
|
+
$logger.info("enabling PDK in metadata.json")
|
73
|
+
metadata = Puppet.module_metadata
|
74
|
+
|
75
|
+
PDK_TAGS.each do |pdk_tag|
|
76
|
+
metadata[pdk_tag] = pdk_metadata[pdk_tag]
|
77
|
+
end
|
78
|
+
PDQTest::Puppet.save_module_metadata(metadata)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.is_pdk_enabled
|
83
|
+
Puppet.module_metadata.include?(PDK_VERSION_TAG)
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.amend_sync_yml(data)
|
87
|
+
if File.exist? SYNC_YML
|
88
|
+
sync = YAML.load_file(SYNC_YML)
|
89
|
+
else
|
90
|
+
sync = {}
|
91
|
+
end
|
92
|
+
sync.deep_merge!(data)
|
93
|
+
$logger.info("Updated .sync.yml with #{data}")
|
94
|
+
|
95
|
+
File.open(SYNC_YML, 'w') { |f| YAML.dump(sync, f) }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# Detection routines for PDQTest 1x files so that we can find and remove them
|
2
|
+
# as part of any PDQTest 2x/PDK upgrade
|
3
|
+
require 'digest/md5'
|
4
|
+
|
5
|
+
module PDQTest
|
6
|
+
module PDQTest1x
|
7
|
+
|
8
|
+
# Urgh... I wish I'd put my own magic marker in these files... then I would
|
9
|
+
# have been able to find them easily(!)
|
10
|
+
# This is a list of known PDQTest integrations and their MD5 sums.
|
11
|
+
# Thankfully I didn't make _too many_ upgrades
|
12
|
+
PDQTEST_FILES = {
|
13
|
+
"Rakefile" => [
|
14
|
+
"3c65c0650e68771854036fbe67fb0f5d",
|
15
|
+
"0254db5d3fc38c67a2c160d7296a24f8"
|
16
|
+
],
|
17
|
+
"spec/spec_helper.rb" => [
|
18
|
+
"8862eca30ed66bc71c1acc7a0da89305",
|
19
|
+
"0db89c9a486df193c0e40095422e19dc",
|
20
|
+
],
|
21
|
+
".rspec" => [
|
22
|
+
"c5f206a3f2387663a941cd9719e4bb00"
|
23
|
+
]
|
24
|
+
}
|
25
|
+
|
26
|
+
# These plus the `pdqtest` gem are the _only_ gems that PDQTest 1x ever used
|
27
|
+
# If we only see these gems and our own, then we are almost certainly safe
|
28
|
+
# to replace the file with the PDK version
|
29
|
+
# List was extracted with some awk-foo
|
30
|
+
# https://gist.github.com/GeoffWilliams/21de190c5f6285b68f777885d92dba72
|
31
|
+
PDQTEST_RUBYGEMS = [
|
32
|
+
/gem 'CFPropertyList'/,
|
33
|
+
/gem 'facter', '>= 1.7.0'/,
|
34
|
+
/gem 'facter', '2.4.6'/,
|
35
|
+
/gem 'facter', '2.5.1'/,
|
36
|
+
/gem 'metadata-json-lint'/,
|
37
|
+
/gem 'puppet'/,
|
38
|
+
/gem 'puppetlabs_spec_helper', '>= 1.0.0'/,
|
39
|
+
/gem 'puppet-lint', '>= 1.0.0'/,
|
40
|
+
/gem 'puppet', puppetversion/,
|
41
|
+
/gem 'puppet-strings'/,
|
42
|
+
/gem 'rake', '~> 10.0'/,
|
43
|
+
/gem 'rspec', '~> 2.0'/,
|
44
|
+
/gem 'rspec-puppet'/,
|
45
|
+
/gem 'rspec-puppet-facts', '1.7.0'/,
|
46
|
+
/gem 'rubocop'/,
|
47
|
+
/gem 'rubocop', '0.47.1'/,
|
48
|
+
/gem 'rubocop', '0.50.0'/,
|
49
|
+
]
|
50
|
+
|
51
|
+
PDQTEST_GEM = /^\s*gem 'pdqtest'/
|
52
|
+
|
53
|
+
# Did PDQTest ever manage this file?
|
54
|
+
def self.was_pdqtest_file(f)
|
55
|
+
[
|
56
|
+
".rspec",
|
57
|
+
"Gemfile",
|
58
|
+
"Rakefile",
|
59
|
+
"spec/fixtures",
|
60
|
+
].include? f
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.is_pdqtest_file(f)
|
64
|
+
detected = false
|
65
|
+
|
66
|
+
if PDQTEST_FILES.include?(f)
|
67
|
+
if File.exist? f
|
68
|
+
# check for known PDQTest files spanning all versions
|
69
|
+
project_md5 = Digest::MD5.file(f).hexdigest
|
70
|
+
if PDQTEST_FILES[f].include?(project_md5)
|
71
|
+
$logger.debug("File at #{f} matches a known PDQTest 1x file")
|
72
|
+
detected = true
|
73
|
+
end
|
74
|
+
else
|
75
|
+
$logger.debug "Missing PDQTest file #{f}"
|
76
|
+
detected = false
|
77
|
+
end
|
78
|
+
elsif f == "Gemfile"
|
79
|
+
if File.exist? f
|
80
|
+
# to detect if PDQTest is the Gemfile, just look for the gem itself
|
81
|
+
if File.readlines(f).grep(PDQTEST_GEM).any?
|
82
|
+
# this project previously used PDQTest, now check to see if there
|
83
|
+
# are any unknown gems in the file
|
84
|
+
$logger.debug("Detected PDQTest 1.x in your Gemfile")
|
85
|
+
detected = true
|
86
|
+
project_gems = File.readlines(f).grep(/^\s*gem /)
|
87
|
+
project_gems.reject { |line|
|
88
|
+
line =~ PDQTEST_GEM
|
89
|
+
}.each { |project_gem|
|
90
|
+
found = false
|
91
|
+
PDQTEST_RUBYGEMS.each { |pdqtest_gem|
|
92
|
+
if project_gem =~ pdqtest_gem
|
93
|
+
$logger.debug "known gem detected: #{project_gem.strip}"
|
94
|
+
found = true
|
95
|
+
end
|
96
|
+
}
|
97
|
+
if ! found
|
98
|
+
$logger.error("unknown gem line in your Gemfile: '#{project_gem.strip}'")
|
99
|
+
detected = false
|
100
|
+
end
|
101
|
+
}
|
102
|
+
end
|
103
|
+
else
|
104
|
+
$logger.debug("missing Gemfile: #{f}")
|
105
|
+
detected = false
|
106
|
+
end
|
107
|
+
else
|
108
|
+
raise("File #{f} was never managed by PDQTest, why are you testing it?")
|
109
|
+
end
|
110
|
+
|
111
|
+
detected
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|