pdqtest 1.4.1 → 1.9.9beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +9 -3
  3. data/doc/acceptance_tests.md +100 -22
  4. data/doc/caching.md +5 -1
  5. data/doc/development.md +16 -5
  6. data/doc/emoji.md +20 -9
  7. data/doc/enabling_testing.md +15 -3
  8. data/doc/examples.md +25 -6
  9. data/doc/hiera.md +30 -11
  10. data/doc/installation.md +59 -8
  11. data/doc/pdk.md +334 -0
  12. data/doc/puppet_facts.md +45 -3
  13. data/doc/puppet_module_dependencies.md +34 -16
  14. data/doc/running_tests.md +35 -15
  15. data/doc/test_generation.md +11 -19
  16. data/doc/tips_and_tricks.md +17 -8
  17. data/doc/troubleshooting.md +19 -8
  18. data/doc/upgrading.md +125 -6
  19. data/doc/windows.md +51 -0
  20. data/docker_images/centos/Dockerfile +4 -3
  21. data/docker_images/centos/Makefile +1 -1
  22. data/docker_images/ubuntu/Dockerfile +3 -3
  23. data/docker_images/windows/Dockerfile +26 -0
  24. data/docker_images/windows/make.ps1 +2 -0
  25. data/exe/pdqtest +73 -28
  26. data/lib/pdqtest/core.rb +1 -1
  27. data/lib/pdqtest/docker.rb +143 -51
  28. data/lib/pdqtest/emoji.rb +33 -7
  29. data/lib/pdqtest/fastcheck.rb +19 -0
  30. data/lib/pdqtest/instance.rb +16 -15
  31. data/lib/pdqtest/logger.rb +35 -0
  32. data/lib/pdqtest/pdk.rb +98 -0
  33. data/lib/pdqtest/pdqtest1x.rb +115 -0
  34. data/lib/pdqtest/puppet.rb +277 -134
  35. data/lib/pdqtest/skeleton.rb +119 -39
  36. data/lib/pdqtest/upgrade.rb +42 -42
  37. data/lib/pdqtest/util.rb +82 -2
  38. data/lib/pdqtest/version.rb +1 -2
  39. data/pdqtest.gemspec +8 -13
  40. data/res/{skeleton → acceptance}/init.bats +0 -0
  41. data/res/{skeleton → acceptance}/init__before.bats +0 -0
  42. data/res/{skeleton → acceptance}/init__setup.sh +0 -0
  43. data/res/skeleton/.puppet-lint.rc +5 -0
  44. data/res/skeleton/{dot_travis.yml → .travis.yml} +0 -0
  45. data/res/skeleton/Makefile +20 -5
  46. data/res/skeleton/make.ps1 +66 -0
  47. data/res/skeleton/spec/fixtures/hiera.yaml +13 -0
  48. data/res/skeleton/spec/fixtures/hieradata/test.yaml +11 -0
  49. data/res/templates/examples_init.pp.erb +1 -1
  50. metadata +47 -115
  51. data/lib/pdqtest/lint.rb +0 -31
  52. data/lib/pdqtest/rspec.rb +0 -69
  53. data/lib/pdqtest/syntax.rb +0 -20
  54. data/res/skeleton/Gemfile +0 -7
  55. data/res/skeleton/Rakefile +0 -3
  56. data/res/skeleton/dot_gitignore +0 -9
  57. data/res/skeleton/dot_rspec +0 -2
  58. data/res/skeleton/hiera.yaml +0 -7
  59. data/res/skeleton/spec_helper.rb +0 -4
  60. data/res/skeleton/test.yaml +0 -3
@@ -6,23 +6,101 @@ module PDQTest
6
6
  OUT = 0
7
7
  ERR = 1
8
8
  STATUS = 2
9
- ENV='export TERM=xterm LC_ALL=C PATH=/usr/local/bats/bin:/opt/puppetlabs/puppet/bin:$PATH;'
9
+ REAL_CMD = 3
10
10
  IMAGES = {
11
- :DEFAULT => 'declarativesystems/pdqtest-1x-centos:2019-04-01-0',
12
- :UBUNTU => 'declarativesystems/pdqtest-ubuntu:2018-08-29-0',
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
- HIERA_YAML_CONTAINER = '/etc/puppetlabs/puppet/hiera.yaml'
15
- HIERA_YAML_HOST = '/spec/fixtures/hiera.yaml'
16
- HIERA_DIR = '/spec/fixtures/hieradata'
17
- YUM_CACHE_CONTAINER = "/var/cache/yum"
18
- YUM_CACHE_HOST = "#{Util::app_dir_expanded}/cache/yum"
19
-
20
- def self.wrap_cmd(cmd)
21
- ['bash', '-c', "#{ENV} #{cmd}"]
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
- container.exec(wrap_cmd(cmd), tty: true)
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
- Escort::Logger.output.puts "Windows acceptance testing not supported yet... any ideas?"
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
- def self.new_container(test_dir, image_name, privileged)
64
- pwd = Dir.pwd
65
- hiera_yaml_host = File.join(pwd, HIERA_YAML_HOST)
66
- hiera_dir = File.join(pwd, HIERA_DIR)
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 ! Dir.exists?(YUM_CACHE_HOST)
80
- FileUtils.mkdir_p(YUM_CACHE_HOST)
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
- # hiera.yaml *must* exist on the host or we will get errors from Docker
84
- if ! File.exists?(hiera_yaml_host)
85
- File.write(hiera_yaml_host, '# hiera configuration for testing')
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
- Escort::Logger.output << l
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
- Escort::Logger.error << l
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(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
- Escort::Logger.output.puts message
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
- Escort::Logger.output.puts lable_string + emoji_pass
49
+ $logger.info lable_string + emoji_pass
24
50
  else
25
51
  # boom! crappy code
26
- Escort::Logger.error.error lable_string + emoji_fail
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, "😬", "💣", label)
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, "😎", "💩", 'Overall')
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
@@ -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
- Escort::Logger.output.puts "No acceptance tests found, annotate examples with #{PDQTest::Puppet::MAGIC_MARKER} to make some"
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
- Escort::Logger.output.puts "Acceptance test on #{test_platforms}..."
56
+ $logger.info "Acceptance test on #{test_platforms}..."
58
57
  test_platforms.each { |image_name|
59
- Escort::Logger.output.puts "--- start test with #{image_name} ---"
60
- @@active_container = PDQTest::Docker::new_container(TEST_DIR, image_name, @@privileged)
61
- Escort::Logger.output.puts "alive, running tests"
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
- Escort::Logger.output.puts "finished build, container #{@@active_container.id} left on system"
66
- Escort::Logger.output.puts " docker exec -ti #{@@active_container.id} bash "
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
- Escort::Logger.output.puts "--- end test with #{image_name} (status: #{status})---"
71
+ $logger.info "--- end test with #{image_name} (status: #{status})---"
73
72
  }
74
73
  end
75
- Escort::Logger.output.puts "overall acceptance test status=#{status}"
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
- Escort::Logger.output.puts "Opening a shell in #{image_name}"
84
- @@active_container = PDQTest::Docker::new_container(TEST_DIR, image_name, @@privileged)
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} bash")
97
+ system("docker exec -ti #{@@active_container.id} #{Util.shell}")
97
98
  if @@keep_container
98
- Escort::Logger.output.puts "finished build, container #{@@active_container.id} left on system"
99
- Escort::Logger.output.puts " docker exec -ti #{@@active_container.id} bash "
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
@@ -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