git-fastclone 1.4.0 → 1.4.2

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: ed5f3f84cbab65351479f22b659b912521699f542c898010527f25b7c3786c84
4
- data.tar.gz: 5f02716656bf0962d9a808ae368078f0e151e6bdfd3abba5b25503504f64194b
3
+ metadata.gz: da2eb17be407c42dbabdb002d8cee1fb56820f6543df47758b0376e84ed2344e
4
+ data.tar.gz: 0c1ca35bca06f608f8087670eba49cb5cc7d6c1af7c308e38159477455bd33c3
5
5
  SHA512:
6
- metadata.gz: a9219567c52c31d5219027adb6227c88970dd839fa8dd2f50258fc205adc3e4f9372d44d6f734242849865d7885f6b8f5a3fadfef05f77c88e24d8d85016a849
7
- data.tar.gz: c136b5240dfc87480457c924772944282f518f8c77d49473f41724449ae0566d8cc5476e6f698aa86de2b18f1f77a8995d0f5f3e8778546630e390d6ed2d2530
6
+ metadata.gz: 4a3d27522c916ac8883ad8abceb5d19529bb406409b3f7904652a54640b2edc91184420baad3118d8379b7c26ce2331018367c994375843c9130ae9511f1108f
7
+ data.tar.gz: 413c42026762c4bf1a80d693d2920c0a519969a7d5c4f215fb810b88f6dabb5e449a15d331214c0751e0daa92c4cbc706915e7ca4d9691ec2aaefb292b8cbef6
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Version string for git-fastclone
4
4
  module GitFastCloneVersion
5
- VERSION = '1.4.0'
5
+ VERSION = '1.4.2'
6
6
  end
data/lib/git-fastclone.rb CHANGED
@@ -74,7 +74,7 @@ module GitFastClone
74
74
  DEFAULT_GIT_ALLOW_PROTOCOL = 'file:git:http:https:ssh'
75
75
 
76
76
  attr_accessor :reference_dir, :prefetch_submodules, :reference_updated, :reference_mutex,
77
- :options, :abs_clone_path, :using_local_repo, :verbose, :color,
77
+ :options, :abs_clone_path, :using_local_repo, :verbose, :print_git_errors, :color,
78
78
  :flock_timeout_secs
79
79
 
80
80
  def initialize
@@ -100,6 +100,8 @@ module GitFastClone
100
100
 
101
101
  self.verbose = false
102
102
 
103
+ self.print_git_errors = false
104
+
103
105
  self.color = false
104
106
 
105
107
  self.flock_timeout_secs = 0
@@ -133,9 +135,15 @@ module GitFastClone
133
135
  end
134
136
 
135
137
  opts.on('-v', '--verbose', 'Verbose mode') do
138
+ puts '--print_git_errors is redundant when using --verbose' if print_git_errors
136
139
  self.verbose = true
137
140
  end
138
141
 
142
+ opts.on('--print_git_errors', 'Print git output if a command fails') do
143
+ puts '--print_git_errors is redundant when using --verbose' if verbose
144
+ self.print_git_errors = true
145
+ end
146
+
139
147
  opts.on('-c', '--color', 'Display colored output') do
140
148
  self.color = true
141
149
  end
@@ -212,13 +220,14 @@ module GitFastClone
212
220
  clone_commands = ['git', 'clone', verbose ? '--verbose' : '--quiet']
213
221
  clone_commands << '--reference' << mirror.to_s << url.to_s << clone_dest
214
222
  clone_commands << '--config' << config.to_s unless config.nil?
215
- fail_pipe_on_error(clone_commands, quiet: !verbose)
223
+ fail_on_error(*clone_commands, quiet: !verbose, print_on_failure: print_git_errors)
216
224
  end
217
225
 
218
226
  # Only checkout if we're changing branches to a non-default branch
219
227
  if rev
220
228
  Dir.chdir(File.join(abs_clone_path, src_dir)) do
221
- fail_pipe_on_error(['git', 'checkout', '--quiet', rev.to_s], quiet: !verbose)
229
+ fail_on_error('git', 'checkout', '--quiet', rev.to_s, quiet: !verbose,
230
+ print_on_failure: print_git_errors)
222
231
  end
223
232
  end
224
233
 
@@ -243,7 +252,8 @@ module GitFastClone
243
252
  submodule_url_list = []
244
253
  output = ''
245
254
  Dir.chdir(File.join(abs_clone_path, pwd).to_s) do
246
- output = fail_on_error('git', 'submodule', 'init', quiet: !verbose)
255
+ output = fail_on_error('git', 'submodule', 'init', quiet: !verbose,
256
+ print_on_failure: print_git_errors)
247
257
  end
248
258
 
249
259
  output.split("\n").each do |line|
@@ -261,10 +271,9 @@ module GitFastClone
261
271
  threads << Thread.new do
262
272
  with_git_mirror(submodule_url) do |mirror, _|
263
273
  Dir.chdir(File.join(abs_clone_path, pwd).to_s) do
264
- fail_pipe_on_error(
265
- ['git', 'submodule', verbose ? nil : '--quiet', 'update', '--reference', mirror.to_s,
266
- submodule_path.to_s].compact, quiet: !verbose
267
- )
274
+ cmd = ['git', 'submodule', verbose ? nil : '--quiet', 'update', '--reference', mirror.to_s,
275
+ submodule_path.to_s].compact
276
+ fail_on_error(*cmd, quiet: !verbose, print_on_failure: print_git_errors)
268
277
  end
269
278
  end
270
279
 
@@ -337,21 +346,13 @@ module GitFastClone
337
346
  # that this repo has been updated on this run of fastclone
338
347
  def store_updated_repo(url, mirror, repo_name, fail_hard)
339
348
  unless Dir.exist?(mirror)
340
- fail_pipe_on_error(
341
- ['git', 'clone', verbose ? '--verbose' : '--quiet', '--mirror', url.to_s,
342
- mirror.to_s], quiet: !verbose
343
- )
349
+ fail_on_error('git', 'clone', verbose ? '--verbose' : '--quiet', '--mirror', url.to_s, mirror.to_s,
350
+ quiet: !verbose, print_on_failure: print_git_errors)
344
351
  end
345
352
 
346
353
  Dir.chdir(mirror) do
347
354
  cmd = ['git', 'remote', verbose ? '--verbose' : nil, 'update', '--prune'].compact
348
- if verbose
349
- fail_pipe_on_error(cmd, quiet: !verbose)
350
- else
351
- # Because above operation might spit out a lot to stderr, we use this to swallow them
352
- # and only display if the operation return non 0 exit code
353
- fail_on_error(*cmd, quiet: !verbose)
354
- end
355
+ fail_on_error(*cmd, quiet: !verbose, print_on_failure: print_git_errors)
355
356
  end
356
357
  reference_updated[repo_name] = true
357
358
  rescue RunnerExecutionRuntimeError => e
@@ -20,37 +20,9 @@ module RunnerExecution
20
20
  end
21
21
  end
22
22
 
23
- # Wrapper around open3.pipeline_r which fails on error.
24
- # and stops users from invoking the shell by accident.
25
- def fail_pipe_on_error(*cmd_list, quiet: false, **opts)
26
- print_command('Running Pipeline:', cmd_list) unless quiet
27
-
28
- env = opts.delete(:env) { {} }
29
- raise ArgumentError, "The :env option must be a hash, not #{env.inspect}" unless env.is_a?(Hash)
30
-
31
- cmd_list.map! { |cmd| shell_safe(cmd).unshift(env) }
32
-
33
- output, *status_list = Open3.pipeline_r(*cmd_list, opts) do |out, wait_threads|
34
- out_reader = Thread.new do
35
- if quiet
36
- output = out.read
37
- else
38
- # Output from pipeline should go to stdout and also get returned for
39
- # processing if necessary.
40
- output = tee(out, STDOUT)
41
- end
42
- out.close
43
- output
44
- end
45
- [out_reader.value] + wait_threads.map(&:value)
46
- end
47
- exit_on_status(output, cmd_list, status_list, quiet: quiet)
48
- end
49
- module_function :fail_pipe_on_error
50
-
51
23
  # Runs a command that fails on error.
52
24
  # Uses popen2e wrapper. Handles bad statuses with potential for retries.
53
- def fail_on_error(*cmd, stdin_data: nil, binmode: false, quiet: false, **opts)
25
+ def fail_on_error(*cmd, stdin_data: nil, binmode: false, quiet: false, print_on_failure: false, **opts)
54
26
  print_command('Running Shell Safe Command:', [cmd]) unless quiet
55
27
  shell_safe_cmd = shell_safe(cmd)
56
28
  retry_times = opts[:retry] || 0
@@ -67,7 +39,9 @@ module RunnerExecution
67
39
  end
68
40
 
69
41
  # Get out with the status, good or bad.
70
- exit_on_status(output, [shell_safe_cmd], [status], quiet: quiet)
42
+ # When quiet, we don't need to print the output, as it is already streamed from popen2e_wrapper
43
+ needs_print_on_failure = quiet && print_on_failure
44
+ exit_on_status(output, [shell_safe_cmd], [status], quiet: quiet, print_on_failure: needs_print_on_failure)
71
45
  end
72
46
  module_function :fail_on_error
73
47
 
@@ -183,20 +157,21 @@ module RunnerExecution
183
157
  # return code of the first one.
184
158
  #
185
159
  # Otherwise returns first argument (output)
186
- def exit_on_status(output, cmd_list, status_list, quiet: false)
160
+ def exit_on_status(output, cmd_list, status_list, quiet: false, print_on_failure: false)
187
161
  status_list.each_index do |index|
188
162
  status = status_list[index]
189
163
  cmd = cmd_list[index]
190
- check_status(cmd, status, output: output, quiet: quiet)
164
+ check_status(cmd, status, output: output, quiet: quiet, print_on_failure: print_on_failure)
191
165
  end
192
166
 
193
167
  output
194
168
  end
195
169
  module_function :exit_on_status
196
170
 
197
- def check_status(cmd, status, output: nil, quiet: false)
171
+ def check_status(cmd, status, output: nil, quiet: false, print_on_failure: false)
198
172
  return if status.exited? && status.exitstatus == 0
199
173
 
174
+ logger.info(output) if print_on_failure
200
175
  # If we exited nonzero or abnormally, print debugging info and explode.
201
176
  if status.exited?
202
177
  logger.debug("Process Exited normally. Exit status:#{status.exitstatus}") unless quiet
@@ -89,7 +89,7 @@ describe GitFastClone::Runner do
89
89
  describe '.clone' do
90
90
  let(:runner_execution_double) { double('runner_execution') }
91
91
  before(:each) do
92
- allow(runner_execution_double).to receive(:fail_pipe_on_error) {}
92
+ allow(runner_execution_double).to receive(:fail_on_error) {}
93
93
  allow(Dir).to receive(:pwd) { '/pwd' }
94
94
  allow(Dir).to receive(:chdir).and_yield
95
95
  allow(subject).to receive(:with_git_mirror).and_yield('/cache', 0)
@@ -97,13 +97,13 @@ describe GitFastClone::Runner do
97
97
  end
98
98
 
99
99
  it 'should clone correctly' do
100
- expect(subject).to receive(:fail_pipe_on_error).with(
101
- ['git', 'checkout', '--quiet', 'PH'],
102
- { quiet: true }
100
+ expect(subject).to receive(:fail_on_error).with(
101
+ 'git', 'checkout', '--quiet', 'PH',
102
+ { quiet: true, print_on_failure: false }
103
103
  ) { runner_execution_double }
104
- expect(subject).to receive(:fail_pipe_on_error).with(
105
- ['git', 'clone', '--quiet', '--reference', '/cache', 'PH', '/pwd/.'],
106
- { quiet: true }
104
+ expect(subject).to receive(:fail_on_error).with(
105
+ 'git', 'clone', '--quiet', '--reference', '/cache', 'PH', '/pwd/.',
106
+ { quiet: true, print_on_failure: false }
107
107
  ) { runner_execution_double }
108
108
 
109
109
  subject.clone(placeholder_arg, placeholder_arg, '.', nil)
@@ -111,26 +111,41 @@ describe GitFastClone::Runner do
111
111
 
112
112
  it 'should clone correctly with verbose mode on' do
113
113
  subject.verbose = true
114
- expect(subject).to receive(:fail_pipe_on_error).with(
115
- ['git', 'checkout', '--quiet', 'PH'],
116
- { quiet: false }
114
+ expect(subject).to receive(:fail_on_error).with(
115
+ 'git', 'checkout', '--quiet', 'PH',
116
+ { quiet: false, print_on_failure: false }
117
117
  ) { runner_execution_double }
118
- expect(subject).to receive(:fail_pipe_on_error).with(
119
- ['git', 'clone', '--verbose', '--reference', '/cache', 'PH', '/pwd/.'],
120
- { quiet: false }
118
+ expect(subject).to receive(:fail_on_error).with(
119
+ 'git', 'clone', '--verbose', '--reference', '/cache', 'PH', '/pwd/.',
120
+ { quiet: false, print_on_failure: false }
121
121
  ) { runner_execution_double }
122
122
 
123
123
  subject.clone(placeholder_arg, placeholder_arg, '.', nil)
124
124
  end
125
125
 
126
126
  it 'should clone correctly with custom configs' do
127
- expect(subject).to receive(:fail_pipe_on_error).with(
128
- ['git', 'clone', '--quiet', '--reference', '/cache', 'PH', '/pwd/.', '--config', 'config'],
129
- { quiet: true }
127
+ expect(subject).to receive(:fail_on_error).with(
128
+ 'git', 'clone', '--quiet', '--reference', '/cache', 'PH', '/pwd/.', '--config', 'config',
129
+ { quiet: true, print_on_failure: false }
130
130
  ) { runner_execution_double }
131
131
 
132
132
  subject.clone(placeholder_arg, nil, '.', 'config')
133
133
  end
134
+
135
+ context 'with printing errors' do
136
+ before(:each) do
137
+ subject.print_git_errors = true
138
+ end
139
+
140
+ it 'prints failures' do
141
+ expect(subject).to receive(:fail_on_error).with(
142
+ 'git', 'clone', '--quiet', '--reference', '/cache', 'PH', '/pwd/.', '--config', 'config',
143
+ { quiet: true, print_on_failure: true }
144
+ ) { runner_execution_double }
145
+
146
+ subject.clone(placeholder_arg, nil, '.', 'config')
147
+ end
148
+ end
134
149
  end
135
150
 
136
151
  describe '.clear_clone_dest_if_needed' do
@@ -298,7 +313,7 @@ describe GitFastClone::Runner do
298
313
  status = double('status')
299
314
  allow(status).to receive(:exitstatus).and_return(1)
300
315
  ex = RunnerExecution::RunnerExecutionRuntimeError.new(status, 'cmd')
301
- allow(subject).to receive(:fail_pipe_on_error) { raise ex }
316
+ allow(subject).to receive(:fail_on_error) { raise ex }
302
317
  expect(FileUtils).to receive(:remove_entry_secure).with(placeholder_arg, force: true)
303
318
  expect do
304
319
  subject.store_updated_repo(placeholder_arg, placeholder_arg, placeholder_arg, true)
@@ -311,7 +326,7 @@ describe GitFastClone::Runner do
311
326
  status = double('status')
312
327
  allow(status).to receive(:exitstatus).and_return(1)
313
328
  ex = RunnerExecution::RunnerExecutionRuntimeError.new(status, 'cmd')
314
- allow(subject).to receive(:fail_pipe_on_error) { raise ex }
329
+ allow(subject).to receive(:fail_on_error) { raise ex }
315
330
  expect(FileUtils).to receive(:remove_entry_secure).with(placeholder_arg, force: true)
316
331
  expect do
317
332
  subject.store_updated_repo(placeholder_arg, placeholder_arg, placeholder_arg, false)
@@ -322,7 +337,7 @@ describe GitFastClone::Runner do
322
337
  let(:placeholder_hash) { {} }
323
338
 
324
339
  it 'should correctly update the hash' do
325
- allow(subject).to receive(:fail_pipe_on_error)
340
+ allow(subject).to receive(:fail_on_error)
326
341
  allow(Dir).to receive(:chdir) {}
327
342
 
328
343
  subject.reference_updated = placeholder_hash
@@ -367,12 +382,6 @@ describe GitFastClone::Runner do
367
382
  let(:expected_commands) { [] }
368
383
 
369
384
  before(:each) do
370
- allow(subject).to receive(:fail_pipe_on_error) { |*params|
371
- command = params[0]
372
- expect(expected_commands.length).to be > 0
373
- expected_command = expected_commands.shift
374
- expect(command).to eq(expected_command)
375
- }
376
385
  allow(subject).to receive(:fail_on_error) { |*params|
377
386
  # last one is an argument `quiet:`
378
387
  command = params.first(params.size - 1)
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2023 Square Inc.
4
+
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'spec_helper'
18
+ require 'git-fastclone'
19
+
20
+ # Integration tests use real demo_tool.sh to inspect the E2E behavior
21
+ describe RunnerExecution do
22
+ subject { described_class }
23
+ let(:external_tool) { "#{__dir__}/../script/spec_demo_tool.sh" }
24
+ let(:logger) { double('logger') }
25
+
26
+ before do
27
+ allow($stdout).to receive(:puts)
28
+ allow(logger).to receive(:info)
29
+ allow(logger).to receive(:debug)
30
+ allow(logger).to receive(:warn)
31
+ allow(RunnerExecution).to receive(:logger).and_return(logger)
32
+ end
33
+
34
+ describe '.fail_on_error' do
35
+ it 'should log failure info on command error' do
36
+ expect(logger).to receive(:info).with("My error output\n")
37
+
38
+ expect do
39
+ described_class.fail_on_error(external_tool, '1', 'My error output', quiet: true,
40
+ print_on_failure: true)
41
+ end.to raise_error(RunnerExecution::RunnerExecutionRuntimeError)
42
+ end
43
+
44
+ it 'should not log failure output on command success' do
45
+ expect($stdout).not_to receive(:info)
46
+
47
+ described_class.fail_on_error(external_tool, '0', 'My success output', quiet: true,
48
+ print_on_failure: true)
49
+ end
50
+
51
+ it 'should not log failure output when not in the quiet mode' do
52
+ expect($stdout).not_to receive(:info)
53
+
54
+ described_class.fail_on_error(external_tool, '0', 'My success output', quiet: false,
55
+ print_on_failure: true)
56
+ end
57
+ end
58
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-fastclone
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Tauraso
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-03-13 00:00:00.000000000 Z
12
+ date: 2023-06-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: colorize
@@ -44,6 +44,7 @@ files:
44
44
  - lib/runner_execution.rb
45
45
  - spec/git_fastclone_runner_spec.rb
46
46
  - spec/git_fastclone_url_helper_spec.rb
47
+ - spec/runner_execution_spec.rb
47
48
  - spec/spec_helper.rb
48
49
  homepage: http://square.github.io/git-fastclone/
49
50
  licenses:
@@ -65,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
66
  - !ruby/object:Gem::Version
66
67
  version: '0'
67
68
  requirements: []
68
- rubygems_version: 3.1.6
69
+ rubygems_version: 3.4.13
69
70
  signing_key:
70
71
  specification_version: 4
71
72
  summary: git-clone --recursive on steroids!