kitchen-transport-express 1.3.1 → 1.4.1

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: 23840e5574cc8a84acfcb87e24a3a4f6c26ea1174a3c5c2bc8390d3fc23843b6
4
- data.tar.gz: eb2165a04339df078065117b00af095b8cba4903d0c5d03233cedfc5b3ac6a8e
3
+ metadata.gz: 747b9b46fe258347afe6a875be3589040dd32a7a0a683f55daf7db89432f56b8
4
+ data.tar.gz: 5718e229fd6b29f60aee5347ac04805e69f105f3b243371710d1533f80fe90e1
5
5
  SHA512:
6
- metadata.gz: 8257d47351212661fd997b9b3397cdcc63f5f998352fd96362cd6d21092aba753943349db7c31688a705acbbec2582e4754f31b2dc57938b5771c3a726bb95f5
7
- data.tar.gz: a3d90892108b59c591f965debb21bb38de8a6eab34f397703660ee5866c7c9a5158bb5a1e90974788d0c41ee8829c95a9457409ab8f4dca62c9b650a17cf2d2a
6
+ metadata.gz: 0ca322124891398ced97700e80c53e5ea8c2b62fda982444919b78e4304127fdad4bd9eae74736cd28e6ce9902cd1c7ee09052d33c4487cdb71d6cb912b9868d
7
+ data.tar.gz: 37bdcf4336a387fc525ed2e8bba704e23adfcc5e50e8d017adf090521afd97dcfbb3ad9d32313c5e8b11542c863499f0e395df328c71c51f25dc4e1bb32104b6
@@ -0,0 +1,47 @@
1
+ name: Ruby Gem
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build + Publish
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ packages: write
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - name: Set up Ruby
18
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
19
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: 3.1
23
+ rubygems: 3.2.3
24
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
25
+
26
+ - name: Publish to GPR
27
+ run: |
28
+ mkdir -p $HOME/.gem
29
+ touch $HOME/.gem/credentials
30
+ chmod 0600 $HOME/.gem/credentials
31
+ printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
32
+ gem build *.gemspec
33
+ gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
34
+ env:
35
+ GEM_HOST_API_KEY: "Bearer ${{secrets.GH_TOKEN}}"
36
+ OWNER: ${{ github.repository_owner }}
37
+
38
+ - name: Publish to RubyGems
39
+ run: |
40
+ mkdir -p $HOME/.gem
41
+ touch $HOME/.gem/credentials
42
+ chmod 0600 $HOME/.gem/credentials
43
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
44
+ gem build *.gemspec
45
+ gem push *.gem
46
+ env:
47
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # kitchen-transport-express CHANGELOG
2
2
 
3
+ ## 1.4.1
4
+ * fix: 👽️ remove remote command that has become incompatible with `test-kitchen >= 3.9.0`
5
+
6
+ ## 1.4.0
7
+ * feat: ♻️ utilize concurrent futures for enhanced parallelism
8
+ * feat: 🔊 enhanced logging
9
+
3
10
  ## 1.3.1
4
11
  * fix: 🐛 ensure directories that only contain dot files get archived
5
12
 
@@ -31,11 +31,24 @@ module Kitchen
31
31
  archive_basename = ::File.basename(path) + ".tgz"
32
32
  archive_full_name = ::File.join(::File.dirname(path), archive_basename)
33
33
  files = all_files(path)
34
- logger.debug("[#{Express::LOG_PREFIX}] #{path} contains #{files.size} files.")
34
+ start_time = Time.now
35
35
  create_archive(path, files, archive_full_name)
36
+ Express.log(logger, "create archive #{File.basename(archive_full_name)} (#{files.size} files)", start_time)
36
37
  archive_full_name
37
38
  end
38
39
 
40
+ # Transfers the archive to the remote host.
41
+ #
42
+ # @param session [Net::SSH::Connection::Session] the SSH session used to connect to the remote host and execute the extract and cleanup commands.
43
+ # @param local [String] the directory in the local sandbox that is being processed.
44
+ # @param remote [String] the remote directory (kitchen_root).
45
+ # @param opts [Hash] the ssh options that came in from the Kitchen instance.
46
+ def scp(session, local, remote, opts = {})
47
+ start_time = Time.now
48
+ session.scp.upload!(local, remote, opts)
49
+ Express.log(logger, "upload #{File.basename(local)} (Thread ID: #{Thread.current.object_id})", start_time)
50
+ end
51
+
39
52
  # Extracts the archive on the remote host.
40
53
  #
41
54
  # @param session [Net::SSH::Connection::Session] the SSH session used to connect to the remote host and execute the extract and cleanup commands.
@@ -44,13 +57,14 @@ module Kitchen
44
57
  def extract(session, local, remote)
45
58
  return unless local.match(/.*\.tgz/)
46
59
 
60
+ start_time = Time.now
47
61
  archive_basename = File.basename(local)
48
- logger.debug("[#{Express::LOG_PREFIX}] Extracting #{::File.join(remote, archive_basename)}")
49
62
  session.open_channel do |channel|
50
63
  channel.request_pty
51
64
  channel.exec("tar -xzf #{::File.join(remote, archive_basename)} -C #{remote} && rm -f #{File.join(remote, archive_basename)}")
52
65
  end
53
66
  session.loop
67
+ Express.log(logger, "extract #{File.basename(local)} (Thread ID: #{Thread.current.object_id})", start_time)
54
68
  end
55
69
 
56
70
  private
@@ -20,7 +20,7 @@ module Kitchen
20
20
  # The version string for Kitchen Transport Express.
21
21
  #
22
22
  # @author Justin Steele <justin.steele@oracle.com>
23
- VERSION = "1.3.1"
23
+ VERSION = "1.4.1"
24
24
  end
25
25
  end
26
26
  end
@@ -27,6 +27,16 @@ module Kitchen
27
27
  class Express
28
28
  # A constant that gets prepended to debugger messages.
29
29
  LOG_PREFIX = "EXPRESS"
30
+
31
+ # Logger class method to unify logging.
32
+ #
33
+ # @param logger [Kitchen::Logger] the logger that was created by the kitchen instance.
34
+ # @param message [String] the message to output.
35
+ # @param start_time [Time] the start time of the process if duration is desired to be part of the message.
36
+ def self.log(logger, message = nil, start_time = nil)
37
+ message = "#{message} (#{Time.now - start_time}s)" if start_time
38
+ logger.debug "[#{Express::LOG_PREFIX}] [#{Time.now.getutc.strftime("%Y-%m-%dT%H:%M:%S%:z")}] #{message}"
39
+ end
30
40
  end
31
41
 
32
42
  # Express SSH Transport Error class.
@@ -51,7 +61,7 @@ module Kitchen
51
61
  # @return [Ssh::Connection] an instance of Kitchen::Transport::ExpressSsh::Connection.
52
62
  def create_new_connection(options, &block)
53
63
  if @connection
54
- logger.debug("[#{Express::LOG_PREFIX}] Shutting previous connection #{@connection}")
64
+ Express.log(logger, "shutting previous connection #{@connection}")
55
65
  @connection.close
56
66
  end
57
67
 
@@ -95,33 +105,35 @@ module Kitchen
95
105
  # @param locals [Array] the top-level list of directories and files to be transfered.
96
106
  # @param remote [String] the remote directory (kitchen_root).
97
107
  # @raise [ExpressFailed] if any of the threads raised an exception.
98
- def upload(locals, remote) # rubocop: disable Metrics/MethodLength
108
+ def upload(locals, remote)
99
109
  return super unless valid_remote_requirements?(remote)
100
110
 
101
- processed_locals = process_locals(locals)
102
- pool, exceptions = thread_pool(processed_locals)
103
- processed_locals.each do |local|
104
- pool.post do
105
- transfer(local, remote, session.options)
106
- rescue => e
107
- exceptions << e.cause
108
- end
109
- end
110
- pool.shutdown
111
- pool.wait_for_termination
112
-
113
- raise ExpressFailed, exceptions.pop unless exceptions.empty?
114
- end # rubocop: enable Metrics/MethodLength
111
+ start_time = Time.now
112
+ processed_local = process_locals(locals)
113
+ futures = create_futures(processed_local, remote)
114
+ all_done = Concurrent::Promise.zip(*futures).execute
115
+ all_done.value!
116
+ rescue => e
117
+ raise ExpressFailed, e.cause.to_s
118
+ ensure
119
+ Express.log(logger, "transport express complete", start_time)
120
+ end
115
121
 
116
122
  private
117
123
 
118
- # Creates the thread pool and exceptions queue.
124
+ # Creates the concurrent futures.
119
125
  #
120
- # @param processed_locals [Array] list of files and archives to be uploaded.
121
- # @return [Array(Concurrent::FixedThreadPool, Queue)]
126
+ # @param locals [Array] list of files and archives to be uploaded.
127
+ # @return [Array(Concurrent::Promise)]
122
128
  # @api private
123
- def thread_pool(processed_locals)
124
- [Concurrent::FixedThreadPool.new([processed_locals.length, 10].min), Queue.new]
129
+ def create_futures(locals, remote)
130
+ # Start upload futures
131
+ executor = Concurrent::FixedThreadPool.new([locals.length, 10].min)
132
+ locals.map do |local|
133
+ Concurrent::Promise.execute(executor: executor) do
134
+ transfer(local, remote, session.options)
135
+ end
136
+ end
125
137
  end
126
138
 
127
139
  # Ensures the remote host has the minimum-required executables to extract the archives.
@@ -131,11 +143,9 @@ module Kitchen
131
143
  # @api private
132
144
  def valid_remote_requirements?(remote)
133
145
  execute("(which tar && which gzip) > /dev/null")
134
- execute("mkdir -p #{remote}")
135
146
  true
136
147
  rescue => e
137
- logger.debug("[#{Express::LOG_PREFIX}] Requirements not met on remote host for Express transport.")
138
- logger.debug("[#{Express::LOG_PREFIX}] #{e}")
148
+ Express.log(logger, "Requirements not met on remote host for Express transport.\n#{e}")
139
149
  false
140
150
  end
141
151
 
@@ -166,13 +176,11 @@ module Kitchen
166
176
  # @raise [StandardError] if the files could not be uploaded successfully.
167
177
  # @api private
168
178
  def transfer(local, remote, opts = {})
169
- logger.debug("[#{Express::LOG_PREFIX}] Transferring #{local} to #{remote}")
170
-
171
179
  Net::SSH.start(session.host, opts[:user], **opts) do |ssh|
172
- ssh.scp.upload!(local, remote, opts)
180
+ scp(ssh, local, remote, opts)
173
181
  extract(ssh, local, remote)
174
182
  rescue Net::SCP::Error => ex
175
- logger.debug("[#{Express::LOG_PREFIX}] upload failed with #{ex.message.strip}")
183
+ Express.log(logger, "upload failed with #{ex.message.strip}")
176
184
  raise "(#{ex.message.strip})"
177
185
  end
178
186
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-transport-express
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Steele
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-11 00:00:00.000000000 Z
11
+ date: 2025-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: test-kitchen
@@ -144,6 +144,7 @@ executables: []
144
144
  extensions: []
145
145
  extra_rdoc_files: []
146
146
  files:
147
+ - ".github/workflows/gem-push.yml"
147
148
  - ".github/workflows/ruby.yml"
148
149
  - ".gitignore"
149
150
  - ".rubocop.yml"
@@ -165,7 +166,7 @@ metadata:
165
166
  documentation_uri: https://github.com/justintsteele/kitchen-transport-express/blob/main/README.md
166
167
  homepage_uri: https://github.com/justintsteele/kitchen-transport-express
167
168
  source_code_uri: https://github.com/justintsteele/kitchen-transport-express
168
- post_install_message:
169
+ post_install_message:
169
170
  rdoc_options: []
170
171
  require_paths:
171
172
  - lib
@@ -181,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
182
  version: '0'
182
183
  requirements: []
183
184
  rubygems_version: 3.3.27
184
- signing_key:
185
+ signing_key:
185
186
  specification_version: 4
186
187
  summary: Skip the long lines in Kitchen Transport!
187
188
  test_files: []