cem_win_spec 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b8483cd4acfa3729cf4bd453fe3ef09a67c71ddd3dcee46f5dc3986e755ddf07
4
- data.tar.gz: a4ef098f7125bf68579dd1b5902d5cb553ccfcbef355d8bd0e4f1d8900eae395
3
+ metadata.gz: 0c99510b91f69ac85f4e529d51134f797546bca8ee7ede74629a08620280b4c6
4
+ data.tar.gz: 57aa64d9931b08ce6a1e49178303643ded631334b43612707ee7383fb8c07426
5
5
  SHA512:
6
- metadata.gz: 8a1a521b044cc4c14a26efd6b8936f662dc1d2b173918337e49b591fe1178f6357aff317cd7dab4ae167688eea2304b75dc89fde8273bb8e7dcc3d22b8df8d33
7
- data.tar.gz: a31a1631d32ca72d34f276920de7a9f22f34175afac7306e64f7158ec309cc66ce0e80aab6b3ac430627f170291b9e442fd7516a7231b242c059a39836f5e3e1
6
+ metadata.gz: bdc2ba16b32de3f4e5eff3f327d5407cb7d377cb836ae971b9c7dd57b771d8b1e7d7347c312006e52e77302c8ff2c61c899d5f82e39336aefa8bfb41dca0e865
7
+ data.tar.gz: 07f97ff0b736be471fea8cd9db08ce10c070353e03c5e523fc301b75a39a6689e77149ea95933d55c7cda5110f93983e562305bf4020472025fadde500293a31
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cem_win_spec (0.1.4)
4
+ cem_win_spec (0.1.6)
5
5
  parallel_tests (~> 3.4)
6
6
  puppet_forge (~> 4.1)
7
7
  winrm (~> 2.3)
@@ -15,7 +15,7 @@ GEM
15
15
  coderay (1.1.3)
16
16
  diff-lcs (1.5.0)
17
17
  erubi (1.12.0)
18
- faraday (2.7.5)
18
+ faraday (2.7.10)
19
19
  faraday-net_http (>= 2.0, < 3.1)
20
20
  ruby2_keywords (>= 0.0.4)
21
21
  faraday-follow_redirects (0.3.0)
@@ -8,6 +8,8 @@ require 'puppet_forge'
8
8
  require 'yaml'
9
9
 
10
10
  module CemWinSpec
11
+ class FixtureCacheError < StandardError; end
12
+
11
13
  # Class for managing cached fixtures
12
14
  # Fixture caching is used to speed up test runs by reusing the same
13
15
  # Puppet modules between test runs instead of downloading them each time.
@@ -24,11 +26,10 @@ module CemWinSpec
24
26
  attr_reader :cache_dir, :cache_entries
25
27
 
26
28
  def initialize
27
- raise 'FixtureCache must be ran on Windows' unless Gem.win_platform?
28
-
29
+ validate_platform!
29
30
  @cache_dir = CACHE_DIR
30
31
  @cache_entries = setup_and_load_cache
31
- @entries_digest = Digest::SHA256.hexdigest(@cache_entries.to_s)
32
+ @entries_digest = hexdigest(@cache_entries.to_s)
32
33
  @dependencies = dependencies_from_metadata
33
34
  setup!
34
35
  end
@@ -43,6 +44,8 @@ module CemWinSpec
43
44
  puts "Downloading #{name} #{data[:version]}..."
44
45
  download_and_cache(name, data[:release_slug], data[:checksum])
45
46
  end
47
+ rescue StandardError => e
48
+ handle_error(e, 'Failed to setup fixture cache')
46
49
  ensure
47
50
  save_cache_entries
48
51
  end
@@ -52,16 +55,37 @@ module CemWinSpec
52
55
  raise "Directory #{fixtures_dir} does not exist" unless File.directory?(fixtures_dir)
53
56
 
54
57
  @cache_entries.each do |_, path|
55
- ::FileUtils.cp_r(path, fixtures_dir)
56
- interim_mod_path = File.join(fixtures_dir, File.basename(path))
57
58
  final_mod_path = File.join(fixtures_dir, File.basename(path).split('-').last)
58
- ::FileUtils.mv(interim_mod_path, final_mod_path)
59
- puts "Copied #{File.basename(path)} to #{final_mod_path}"
59
+ ::FileUtils.remove_entry_secure(final_mod_path) if File.exist?(final_mod_path)
60
+ ::FileUtils.cp_r(path, final_mod_path)
61
+ puts "Copied #{path} to #{final_mod_path}"
60
62
  end
63
+ rescue StandardError => e
64
+ handle_error(e, "Failed to copy fixtures to #{fixtures_dir}")
61
65
  end
62
66
 
63
67
  private
64
68
 
69
+ def validate_platform!
70
+ return if Gem.win_platform?
71
+
72
+ $stderr.puts 'ERROR: FixtureCache must run on Windows'
73
+ raise FixtureCacheError, 'FixtureCache must run on Windows'
74
+ end
75
+
76
+ def hexdigest(str)
77
+ Digest(:SHA256).hexdigest(str)
78
+ end
79
+
80
+ def handle_error(e, msg = 'Fixture cache error')
81
+ $stderr.puts "ERROR: #{msg}: #{e}"
82
+ raise e if e.is_a?(FixtureCacheError)
83
+
84
+ new_err = FixtureCacheError.new("#{msg}: #{e}")
85
+ new_err.set_backtrace(e.backtrace)
86
+ raise new_err
87
+ end
88
+
65
89
  def dependencies_from_metadata
66
90
  raise "File metadata.json not found in current directory #{Dir.pwd}" unless File.exist?('metadata.json')
67
91
 
@@ -81,6 +105,8 @@ module CemWinSpec
81
105
  release_slug: latest_valid_release.slug,
82
106
  }
83
107
  end
108
+ rescue StandardError => e
109
+ handle_error(e, 'Failed to get dependencies from metadata.json')
84
110
  end
85
111
 
86
112
  def dep_version_req_satisfied?(version_req, version)
@@ -88,6 +114,8 @@ module CemWinSpec
88
114
  raise "Invalid version requirement #{version_req}" unless reqs.to_a.length > 1
89
115
 
90
116
  reqs.to_a[1..-1].all? { |req| version_req_satisfied?(req, version) }
117
+ rescue StandardError => e
118
+ handle_error(e, 'Failed checking version requirement satisfaction')
91
119
  end
92
120
 
93
121
  def version_req_satisfied?(version_req, version)
@@ -95,7 +123,7 @@ module CemWinSpec
95
123
  end
96
124
 
97
125
  def module_checksum(name, version_req, version)
98
- Digest::SHA256.hexdigest("#{name}#{version_req}#{version}")
126
+ hexdigest("#{name}#{version_req}#{version}")
99
127
  end
100
128
 
101
129
  def manifest
@@ -114,6 +142,8 @@ module CemWinSpec
114
142
  end
115
143
  puts "Loading cache manifest #{manifest}..."
116
144
  YAML.load_file(manifest)
145
+ rescue StandardError => e
146
+ handle_error(e, 'Failed to setup and load cache')
117
147
  end
118
148
 
119
149
  def cached?(checksum)
@@ -132,13 +162,17 @@ module CemWinSpec
132
162
  File.join(module_cache_dir, 'temp'))
133
163
  cache_entries[checksum] = File.join(module_cache_dir, name)
134
164
  puts "Downloaded #{release_slug} to #{File.join(module_cache_dir, name)}"
165
+ rescue StandardError => e
166
+ handle_error(e, "Failed to download and cache #{name} with slug #{release_slug} and checksum #{checksum}")
135
167
  end
136
168
 
137
169
  def save_cache_entries
138
- return if @entries_digest == Digest::SHA256.hexdigest(cache_entries.to_s)
170
+ return if @entries_digest == hexdigest(cache_entries.to_s)
139
171
 
140
172
  File.write(manifest, cache_entries.to_yaml)
141
173
  puts "Saved cache manifest #{manifest}"
174
+ rescue StandardError => e
175
+ handle_error(e, "Failed to save cache manifest #{manifest}")
142
176
  end
143
177
  end
144
178
  end
@@ -8,50 +8,37 @@ module CemWinSpec
8
8
  class ModuleArchiveBuilder
9
9
  include CemWinSpec::Logging
10
10
 
11
- FILE_ALLOWLIST = %w[
12
- data
13
- files
14
- lib
15
- manifests
16
- plans
17
- spec
18
- tasks
19
- types
20
- .fixtures.yml
21
- .gitignore
22
- .rspec
23
- .rubocop.yml
24
- .yardopts
25
- hiera.yaml
26
- Gemfile
27
- metadata.json
28
- Rakefile
11
+ FILE_EXCLUDELIST = %w[
12
+ .git/**/*
13
+ data/benchmarks/**/*
14
+ dev/**/*
15
+ spec/fixtures/modules/*
16
+ pkg/**/*
17
+ Gemfile.lock
29
18
  ].freeze
30
19
 
31
- attr_reader :module_dir, :allowlist, :tempdir, :archive
20
+ attr_reader :module_dir, :excludelist, :tempdir, :archive
32
21
 
33
- def initialize(module_dir = Dir.pwd, allowlist: FILE_ALLOWLIST)
22
+ def initialize(module_dir = Dir.pwd, excludelist: FILE_EXCLUDELIST)
34
23
  @module_dir = module_dir
35
24
  @module_name = File.basename(module_dir)
36
- @allowlist = allowlist
25
+ @excludelist = excludelist
37
26
  end
38
27
 
39
28
  alias path archive
40
29
 
41
- def build
30
+ def build(remove_when_complete: true)
42
31
  create_tempdir
43
32
  copy_module_to_tempdir
44
33
  remove_unwanted_files
45
34
  create_archive
46
35
  if block_given?
47
36
  begin
48
- yield archive
49
- ensure
50
- FileUtils.rm_rf(archive) if archive && File.exist?(archive)
37
+ yield File.join(tempdir, archive)
51
38
  end
52
39
  end
53
40
  ensure
54
- FileUtils.rm_rf(tempdir) if tempdir && File.exist?(tempdir)
41
+ FileUtils.rm_rf(tempdir) if remove_when_complete && tempdir && File.exist?(tempdir)
55
42
  end
56
43
 
57
44
  private
@@ -62,22 +49,30 @@ module CemWinSpec
62
49
  end
63
50
 
64
51
  def copy_module_to_tempdir
65
- FileUtils.cp_r(module_dir, tempdir)
52
+ FileUtils.cp_r(module_dir, tempdir, preserve: false)
66
53
  logger.debug "Copied #{module_dir} to #{tempdir}"
67
54
  @temp_module_dir = File.join(tempdir, @module_name)
68
55
  end
69
56
 
70
- def remove_unwanted_files
71
- to_remove = Dir.glob("*", File::FNM_DOTMATCH, base: @temp_module_dir).reject { |f| allowlist.include?(f) || %w[. ..].include?(f) }
72
- to_remove.each do |file|
73
- FileUtils.rm_rf(File.join(@temp_module_dir, file))
74
- logger.debug "Removed #{file} from #{@temp_module_dir}"
57
+ def unwanted_files
58
+ unwanted = []
59
+ Dir.glob('**/*', File::FNM_DOTMATCH, base: @temp_module_dir) do |f|
60
+ next if %w[. ..].include?(f)
61
+
62
+ unwanted << File.join(@temp_module_dir, f) if excludelist.any? { |e| File.fnmatch?(e, f, File::FNM_DOTMATCH) }
75
63
  end
64
+ unwanted
65
+ end
66
+
67
+ def remove_unwanted_files
68
+ FileUtils.rm_rf(unwanted_files, verbose: (logger.level.first <= Logger::DEBUG))
76
69
  end
77
70
 
78
71
  def create_archive
79
72
  @archive = "#{@module_name}.tar.gz"
80
- `tar -czf #{archive} -C #{tempdir} #{@module_name}`
73
+ Dir.chdir(tempdir) do
74
+ `COPYFILE_DISABLE=1 tar -czf #{archive} --no-acls --no-xattrs #{@module_name}`
75
+ end
81
76
  logger.info "Created module archive #{archive}"
82
77
  end
83
78
  end
@@ -81,7 +81,7 @@ namespace 'cem_win_spec' do
81
81
  task :prep do
82
82
  puts 'Preparing spec data...'
83
83
  data_fix = cem_win_spec_base_path_in_fixtures(cem_win_spec_data_dir)
84
- if File.directory?(data_fix)
84
+ if Dir.exist?(data_fix)
85
85
  puts "Removing old #{data_fix} directory..."
86
86
  ::FileUtils.remove_entry_secure(data_fix)
87
87
  end
@@ -91,16 +91,23 @@ namespace 'cem_win_spec' do
91
91
  raise 'Spec data copy failed!'
92
92
  end
93
93
  hiera_fix = cem_win_spec_base_path_in_fixtures(cem_win_spec_hiera_conf)
94
+ if File.file?(hiera_fix)
95
+ puts "Removing old #{hiera_fix} file..."
96
+ ::FileUtils.remove_entry_secure(hiera_fix)
97
+ end
94
98
  puts "Copying Hiera config to #{hiera_fix}..."
95
99
  ::FileUtils.cp(cem_win_spec_hiera_conf, hiera_fix)
96
- unless File.exist?(hiera_fix)
97
- raise 'Hiera config copy failed!'
98
- end
100
+ raise 'Hiera config copy failed!' unless File.exist?(hiera_fix)
101
+
99
102
  puts 'Spec data prepared successfully'
100
- puts 'Preparing module fixtures...'
101
- mod_fix = cem_win_spec_base_path_in_fixtures('modules')
103
+ puts 'Setting up module fixture cache...'
102
104
  cache = CemWinSpec::FixtureCache.new
105
+ puts 'Copying module fixtures to spec fixtures directory...'
106
+ mod_fix = cem_win_spec_base_path_in_fixtures('modules')
103
107
  cache.copy_fixtures_to(mod_fix)
108
+ puts 'Removing old module symlink...'
109
+ link_path = File.join(mod_fix, 'cem_windows')
110
+ ::FileUtils.remove_entry_secure(link_path) if File.exist?(link_path)
104
111
  puts 'Module fixtures prepared successfully'
105
112
  end
106
113
 
@@ -108,9 +115,10 @@ namespace 'cem_win_spec' do
108
115
  task :parallel_spec_standalone do
109
116
  spec_files = Rake::FileList[cem_win_spec_pattern]
110
117
  pargs = ['--type', 'rspec']
111
- pargs << '--trace' if cem_win_spec_trace
118
+ pargs << '--verbose' if cem_win_spec_trace
112
119
  rspec_args = ['--']
113
120
  rspec_args << '--fail-fast' if cem_win_spec_fail_fast
121
+ rspec_args << '--backtrace' if cem_win_spec_trace
114
122
  rspec_args.concat(['--format', cem_win_spec_format])
115
123
  pargs.concat(rspec_args)
116
124
  pargs << '--'
@@ -68,7 +68,7 @@ module CemWinSpec
68
68
  module_archive_build { |a| remote_upload(a, remote_working_dir) }
69
69
  module_dir = "#{remote_working_dir}\\#{File.basename(module_archive_path, '.tar.gz')}"
70
70
  logger.debug "Module uploaded to #{module_dir}.tar.gz, extracting..."
71
- remote_run("tar -xzf #{module_dir}.tar.gz -C #{remote_working_dir}")
71
+ remote_run("tar -C #{remote_working_dir} -xzf #{module_dir}.tar.gz")
72
72
  logger.debug "Module extracted to #{module_dir}"
73
73
  module_dir
74
74
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CemWinSpec
4
- VERSION = "0.1.4"
4
+ VERSION = "0.1.6"
5
5
  end
@@ -29,8 +29,8 @@ module CemWinSpec
29
29
  begin
30
30
  shell = conn.shell(:powershell)
31
31
  output = shell.run(command(cmd)) do |stdout, stderr|
32
- logger << stdout unless stdout.nil? || stdout.empty?
33
- logger << stderr unless stderr.nil? || stderr.empty?
32
+ logger << stdout if stdout
33
+ logger << stderr if stderr
34
34
  end
35
35
  rescue WinRM::WinRMAuthorizationError => e
36
36
  @available = false
data/lib/cem_win_spec.rb CHANGED
@@ -56,16 +56,37 @@ module CemWinSpec
56
56
  raise ArgumentError, "Unknown operation: #{operation}"
57
57
  end
58
58
  rescue StandardError => e
59
- logger.fatal "Error: #{e.message}"
60
- logger.debug e.backtrace.join("\n")
61
- exit 1
59
+ if operation == :spec
60
+ begin
61
+ logger.warn "Error running spec: #{e.message}"
62
+ logger.debug e.backtrace.join("\n")
63
+ retry_spec_on_error(runner, module_dir, **options)
64
+ rescue StandardError => err
65
+ handle_run_error(err)
66
+ end
67
+ else
68
+ handle_run_error(e)
69
+ end
62
70
  end
63
71
  end
64
72
 
73
+ def self.handle_run_error(err)
74
+ logger.fatal "Error: #{err.message}"
75
+ logger.debug err.backtrace.join("\n")
76
+ exit 1
77
+ end
78
+
79
+ def self.retry_spec_on_error(runner, module_dir, **options)
80
+ logger.info 'Cleaning cache and trying again...'
81
+ clean_fixture_cache_out = clean_fixture_cache(runner, module_dir, **options)
82
+ check_output!(clean_fixture_cache_out, runner)
83
+ spec_out = run_spec(runner, module_dir, **options)
84
+ check_output!(spec_out, runner)
85
+ end
86
+
65
87
  def self.setup_remote_environment(runner)
66
88
  runner.enable_long_paths.run
67
89
  runner.enable_symlinks.run
68
- runner.enable_symlinks.run
69
90
  working_dir_out = runner.create_working_dir.run
70
91
  working_dir = working_dir_out.stdout.chomp
71
92
  logger.debug "Working dir: #{working_dir}"
@@ -99,8 +120,7 @@ module CemWinSpec
99
120
  def self.check_output!(output, runner = nil)
100
121
  unless output.success?
101
122
  runner&.iap_tunnel&.stop(wait: false, log: false)
102
- logger.fatal "Command failed with exit code #{output.exitcode}"
103
- exit output.exitcode
123
+ raise "Command failed with exit code #{output.exitcode}"
104
124
  end
105
125
  end
106
126
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cem_win_spec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Heston Snodgrass
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-31 00:00:00.000000000 Z
11
+ date: 2023-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: winrm
@@ -139,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
139
  - !ruby/object:Gem::Version
140
140
  version: '0'
141
141
  requirements: []
142
- rubygems_version: 3.4.10
142
+ rubygems_version: 3.4.18
143
143
  signing_key:
144
144
  specification_version: 4
145
145
  summary: Write a short summary, because RubyGems requires one.