squared 0.6.1 → 0.6.3

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.
@@ -154,12 +154,8 @@ module Squared
154
154
  task action, [:command] do |_, args|
155
155
  command = param_guard(action, 'command', args: args, key: :command)
156
156
  args = args.extras
157
- a = args.delete('a') || args.delete('all')
158
157
  ls = case command
159
- when 'network'
160
- a = nil
161
- 'ls'
162
- when 'image', 'container'
158
+ when 'image', 'container', 'network'
163
159
  'ls'
164
160
  when 'compose'
165
161
  'ps'
@@ -167,7 +163,7 @@ module Squared
167
163
  raise_error ArgumentError, 'unrecognized command', hint: command
168
164
  end
169
165
  data = VAL_DOCKER[:ls][command.to_sym]
170
- if args.delete('s') || args.delete('standard')
166
+ if has_value!(args, 's', 'standard')
171
167
  cols = data.first(data.index('CreatedAt'))
172
168
  else
173
169
  cols = []
@@ -184,7 +180,8 @@ module Squared
184
180
  cols = choice_index('Select a column', data, multiple: true, force: true, attempts: 1)
185
181
  end
186
182
  end
187
- cmd = docker_output(command, ls, a && '-a')
183
+ cmd = docker_output command, ls
184
+ cmd << '-a' unless command == 'network' || !has_value!(args, 'a', 'all')
188
185
  cmd << quote_option('format', "table #{cols.map! { |val| "{{.#{val}}}" }.join("\t")}")
189
186
  run(cmd, banner: false, from: :ls)
190
187
  end
@@ -225,7 +222,7 @@ module Squared
225
222
 
226
223
  case flag
227
224
  when :exec, :run
228
- format_desc action, flag, "service|:,command#{flag == :exec ? '' : '?'}|::,args*,opts*"
225
+ format_desc action, flag, "service|:,command#{'?' unless flag == :exec}|::,args*,opts*"
229
226
  task flag, [:service] do |_, args|
230
227
  service = param_guard(action, flag, args: args, key: :service)
231
228
  compose!(flag, args.extras, service: service)
@@ -480,8 +477,8 @@ module Squared
480
477
  end
481
478
  elsif all.include?(k)
482
479
  unless type
483
- VAL_DOCKER[:run].each_pair do |key, val|
484
- next unless val.include?(k)
480
+ VAL_DOCKER[:run].each_pair do |key, a|
481
+ next unless a.include?(k)
485
482
 
486
483
  type = key.to_s unless key == :common
487
484
  break
@@ -496,7 +493,7 @@ module Squared
496
493
  v = shell_quote(v, option: false, force: false) if q == ''
497
494
  end
498
495
  args << "#{k}=#{q + v + q}"
499
- elsif verbose
496
+ elsif !silent?
500
497
  log_message(Logger::INFO, 'unrecognized option', subject: from, hint: k)
501
498
  end
502
499
  end
@@ -526,7 +523,7 @@ module Squared
526
523
  else
527
524
  '--disable-content-trust'
528
525
  end
529
- opts << '--quiet' unless verbose
526
+ opts << '--quiet' if silent?
530
527
  return image(:push, opts, id: latest, registry: registry)
531
528
  else
532
529
  if op.empty?
@@ -807,14 +804,14 @@ module Squared
807
804
  unless y
808
805
  bb = index.to_s
809
806
  cc = bb.size.succ
810
- a = sub_style(ee, styles: theme[:inline])
811
- b = "Execute #{sub_style(flag, styles: theme[:active])} on #{a.subhint(ee == id ? nil : id)}"
807
+ a = sub_style ee, theme[:inline]
808
+ b = "Execute #{sub_style(flag, theme[:active])} on #{a.subhint(ee == id ? nil : id)}"
812
809
  e = time_format(time_since(data['CreatedAt']), pass: ['ms'])
813
- f = sub_style(ARG[:BORDER][0], styles: theme[:inline])
810
+ f = sub_style ARG[:BORDER][0], theme[:inline]
814
811
  g = ' ' * cc.succ
815
- h = "#{sub_style(bb.rjust(cc), styles: theme[:current])} #{f} "
812
+ h = "#{sub_style(bb.rjust(cc), theme[:current])} #{f} "
816
813
  puts unless index == 1
817
- puts (h + sub_style(aa, styles: theme[:subject])).subhint("created #{e} ago")
814
+ puts (h + sub_style(aa, theme[:subject])).subhint("created #{e} ago")
818
815
  cols = %w[Tag Status Ports]
819
816
  cols << case flag
820
817
  when :connect, :disconnect
@@ -828,7 +825,7 @@ module Squared
828
825
  puts "#{g + f} #{key}: #{Array(data[key]).join(', ')}" unless data[key].to_s.empty?
829
826
  end
830
827
  w = 9 + flag.to_s.size + 4 + ee.size
831
- puts g + sub_style(ARG[:BORDER][6] + (ARG[:BORDER][1] * w), styles: theme[:inline])
828
+ puts g + sub_style(ARG[:BORDER][6] + (ARG[:BORDER][1] * w), theme[:inline])
832
829
  index += 1
833
830
  next unless confirm("#{h + b}?", no ? 'N' : 'Y')
834
831
 
@@ -858,9 +855,9 @@ module Squared
858
855
  ])
859
856
  printsucc
860
857
  a = t.last.capitalize
861
- b = sub_style(target, styles: theme[:subject])
862
- c = as && sub_style(as, styles: theme[:inline])
863
- confirm "#{a} #{b}#{c ? " as #{c}" : ''}?", 'N'
858
+ b = sub_style target, theme[:subject]
859
+ c = sub_style as, theme[:inline] if as
860
+ confirm "#{a} #{b}#{" as #{c}" if c}?", 'N'
864
861
  end
865
862
 
866
863
  def choice_command(flag, *action)
@@ -926,7 +923,7 @@ module Squared
926
923
  end
927
924
  cmd.merge(Array(out).map! { |val| parse.call(val) })
928
925
  cmd << args
929
- success?(run(cmd), ctx.start_with?(/(?:network|tag|save)/))
926
+ success?(run(cmd), ctx.start_with?(/network|tag|save/))
930
927
  end
931
928
 
932
929
  def filetype(val = dockerfile)
@@ -949,8 +946,7 @@ module Squared
949
946
  end
950
947
 
951
948
  def tagjoin(*args, char: '/')
952
- args.compact!
953
- args.join(char) unless args.empty?
949
+ args.join(char) unless (args = args.compact).empty?
954
950
  end
955
951
 
956
952
  def tagname(val)
@@ -21,17 +21,20 @@ module Squared
21
21
  end
22
22
  elsif uri
23
23
  data[name.to_s] = uri
24
- elsif name.is_a?(Enumerable)
25
- data = name.to_h
26
- elsif name.is_a?(String) && name.match?(GIT_PROTO)
27
- base = name
28
- @project.each_value { |proj| repo << proj if !proj.parent && check.call(proj) }
29
24
  else
30
- warn log_message(Logger::WARN, name, subject: 'git', hint: 'invalid') if warning
31
- return self
25
+ case name
26
+ when Enumerable
27
+ data = name.to_h
28
+ when GIT_PROTO
29
+ base = name.to_s
30
+ each { |proj| repo << proj if !proj.parent && check.call(proj) }
31
+ else
32
+ warn log_message(Logger::WARN, name, subject: 'git', hint: 'invalid') if warning
33
+ return self
34
+ end
32
35
  end
33
36
  if base
34
- base = base.match?(GIT_PROTO) ? "#{base.chomp('/')}/" : @root + base
37
+ base = base.match?(GIT_PROTO) ? "#{base.chomp('/')}/" : rootpath(base)
35
38
  repo.each do |target|
36
39
  if target.is_a?(Project::Git)
37
40
  data[target.localname] = target.project
@@ -50,7 +53,7 @@ module Squared
50
53
  end
51
54
  unless uri.match?(GIT_PROTO) || Pathname.new(uri).absolute?
52
55
  if uri.start_with?('.')
53
- uri = @root + uri
56
+ uri = rootpath uri
54
57
  elsif base
55
58
  uri = base + uri
56
59
  else
@@ -144,6 +147,7 @@ module Squared
144
147
  @revlock = false
145
148
  end
146
149
  end
150
+
147
151
  Application.include Git
148
152
 
149
153
  module Project
@@ -154,9 +158,9 @@ module Squared
154
158
  namespace=p].freeze,
155
159
  add: %w[A e|edit f|force ignore-errors ignore-missing i|interactive n|dry-run p|patch pathspec-file-nul
156
160
  refresh renormalize sparse u|update v|verbose chmod=b pathspec-from-file=p].freeze,
157
- branch: %w[a|all create-reflog i|ignore-case omit-empty q|quiet r|remotes v|verbose abbrev=i color=b column=b
158
- contains=b format=q merged=b no-contains=b no-merged=b points-at=b u|set-upstream-to=b sort=q
159
- t|track=b].freeze,
161
+ branch: %w[a|all create-reflog i|ignore-case omit-empty q|quiet r|remotes v|verbose=+ abbrev=i color=b
162
+ column=b contains=b format=q merged=b no-contains=b no-merged=b points-at=b u|set-upstream-to=b
163
+ sort=q t|track=b].freeze,
160
164
  checkout: %w[l d|detach f|force ignore-other-worktrees ignore-skip-worktree-bits m|merge p|patch
161
165
  pathspec-file-nul q|quiet ours theirs conflict=b orphan=b pathspec-from-file=p t|track=b].freeze,
162
166
  diff: {
@@ -183,9 +187,9 @@ module Squared
183
187
  A|after-context=i B|before-context=i color=b C|context=i m|max-count=n max-depth=i
184
188
  open-files-in-pager=b threads=n].freeze,
185
189
  mv: %w[k f|force n|dry-run v|verbose].freeze,
186
- revert: %w[e S=bm? abort continue n|no-commit quit reference skip cleanup=b gpg-sign=b? m|mainline=i
187
- s|signoff strategy=b X|strategy-option=b].freeze,
188
- rm: %w[r cached f|force n|dry-run ignore-unmatch pathspec-file-nul q|quiet sparse v|verbose
190
+ revert: %w[e S=bm? n|no-commit reference cleanup=b gpg-sign=b? m|mainline=i s|signoff strategy=b
191
+ X|strategy-option=b].freeze,
192
+ rm: %w[r cached f|force n|dry-run ignore-unmatch pathspec-file-nul q|quiet sparse
189
193
  pathspec-from-file=p].freeze
190
194
  }.freeze,
191
195
  log: {
@@ -245,7 +249,7 @@ module Squared
245
249
  pop: %w[index].freeze,
246
250
  apply: %w[index].freeze
247
251
  }.freeze,
248
- status: %w[z u=bm? b|branch long s|short show-stash v|verbose column=b find-renames=i? ignore-submodules=b?
252
+ status: %w[z u=bm? b|branch long s|short show-stash v|verbose=+ column=b find-renames=i? ignore-submodules=b?
249
253
  ignored=b? porcelain=b? untracked-files=b?].freeze,
250
254
  submodule: {
251
255
  status: %w[cached recursive].freeze,
@@ -296,7 +300,8 @@ module Squared
296
300
  send: %w[continue skip abort quit].freeze,
297
301
  value: %w[true false merges interactive].freeze
298
302
  }.freeze,
299
- reset: %w[soft mixed hard merge keep recurse-submodules no-recurse-submodules].freeze
303
+ reset: %w[soft mixed hard merge keep recurse-submodules no-recurse-submodules].freeze,
304
+ revbuild: %w[untracked-files ignore-submodules ignored].freeze
300
305
  }.freeze
301
306
  private_constant :OPT_GIT, :VAL_GIT
302
307
 
@@ -322,7 +327,7 @@ module Squared
322
327
  'fetch' => %i[origin remote all].freeze,
323
328
  'files' => %i[cached modified deleted others].freeze,
324
329
  'git' => %i[add blame clean grep mv revert rm status].freeze,
325
- 'log' => %i[view between contain].freeze,
330
+ 'log' => %i[view grep between contain].freeze,
326
331
  'merge' => %i[commit no-commit send].freeze,
327
332
  'pull' => %i[origin remote all].freeze,
328
333
  'rebase' => %i[branch onto send].freeze,
@@ -565,6 +570,37 @@ module Squared
565
570
  path2 = param_guard(action, flag, args: args, key: :path2)
566
571
  diff(flag, refs: [path1, path2, args.patch])
567
572
  end
573
+ when :grep
574
+ format_desc action, flag, 'pattern+,a/ll-match?,in/vert-grep?,i/E/F/P?,max-count?=i,f/ormat?=s'
575
+ task flag do |_, args|
576
+ grep = args.to_a
577
+ opts = ['oneline']
578
+ while (last = grep.pop)
579
+ case last
580
+ when '--'
581
+ grep << '--' if grep.empty?
582
+ break
583
+ when 'a', 'all-match'
584
+ opts << 'all-match'
585
+ when 'in', 'invert-grep'
586
+ opts << 'invert-grep'
587
+ when 'i', 'E', 'F', 'P'
588
+ opts << last
589
+ else
590
+ if last =~ /^(?:f(?:-ormat)?)=(.+)$/
591
+ opts.shift
592
+ opts << "format=#{$1}"
593
+ elsif last =~ /^(?:max(?:-count)?)=(\d+)$/
594
+ opts << "max-count=#{$1}"
595
+ else
596
+ grep << last
597
+ break
598
+ end
599
+ end
600
+ end
601
+ param_guard(action, flag, args: grep)
602
+ log!(flag, opts, grep: grep)
603
+ end
568
604
  end
569
605
  when 'checkout'
570
606
  case flag
@@ -658,7 +694,7 @@ module Squared
658
694
  branch(flag, target: target, ref: ref, remote: remote)
659
695
  end
660
696
  when :delete
661
- format_desc action, flag, '(^~)name*,:?'
697
+ format_desc action, flag, '[^~]name*,:?'
662
698
  task flag do |_, args|
663
699
  refs = args.to_a
664
700
  if refs.empty? || (r = refs.last == ':')
@@ -1077,9 +1113,18 @@ module Squared
1077
1113
  end
1078
1114
  option('local', strict: true) { |val| opts[:local] = val != '0' }
1079
1115
  option('bare') { |val| opts[:bare] = val }
1116
+ option('single-branch', ignore: false) do |val|
1117
+ opts[:'single-branch'] = val != '0' && val != 'false'
1118
+ opts.delete(:'no-single-branch')
1119
+ end
1120
+ option('no-checkout') do
1121
+ opts[:'no-checkout'] = true
1122
+ opts.delete(:n)
1123
+ end
1124
+ option('no-tags') { opts[:'no-tags'] = true }
1080
1125
  opts.delete(:'recurse-submodules') || opts.delete(:'no-recurse-submodules') if append_submodules(from: :clone)
1081
1126
  append_hash opts
1082
- cmd << '--quiet' unless verbose
1127
+ cmd << '--quiet' if option('quiet') || !verbose
1083
1128
  append_value(data[0], path, delim: true)
1084
1129
  source(banner: sync && !quiet?, multiple: !sync || quiet?)
1085
1130
  end
@@ -1135,8 +1180,8 @@ module Squared
1135
1180
  end
1136
1181
  op.clear
1137
1182
  when :clear
1138
- n = sub_style(file.read.lines.size, styles: theme[:inline])
1139
- s = sub_style(name, styles: theme[:active])
1183
+ n = sub_style file.read.lines.size, theme[:inline]
1184
+ s = sub_style name, theme[:active]
1140
1185
  source(stdout: true) if confirm("Remove #{n} stash entries from #{s}?", 'N')
1141
1186
  return
1142
1187
  when :list
@@ -1151,7 +1196,7 @@ module Squared
1151
1196
  append_option(OptionPartition.select(OPT_GIT[:stash][:push], no: false), no: true, ignore: false)
1152
1197
  append_message
1153
1198
  end
1154
- source(banner: !quiet?, sync: sync, **threadargs)
1199
+ source(sync: sync, banner: !quiet?, **threadargs)
1155
1200
  end
1156
1201
 
1157
1202
  def status(flag = nil, opts = [])
@@ -1196,7 +1241,7 @@ module Squared
1196
1241
  end
1197
1242
 
1198
1243
  def revbuild(flag = nil, opts = [], sync: nil, **kwargs)
1199
- statusargs = lambda do
1244
+ kw = lambda do
1200
1245
  {
1201
1246
  include: relativepath(Array(kwargs[:include]), all: true),
1202
1247
  exclude: relativepath(Array(kwargs[:exclude]), all: true)
@@ -1204,9 +1249,9 @@ module Squared
1204
1249
  end
1205
1250
  unless workspace.closed
1206
1251
  if @revbuild
1207
- statusargs.call.each { |key, val| @revbuild[key] += val }
1252
+ kw.call.each { |key, val| @revbuild[key] += val }
1208
1253
  else
1209
- @revbuild = statusargs.call
1254
+ @revbuild = kw.call
1210
1255
  end
1211
1256
  return
1212
1257
  end
@@ -1214,31 +1259,31 @@ module Squared
1214
1259
  return if sha.empty?
1215
1260
 
1216
1261
  sync = invoked_sync?('revbuild', flag) if sync.nil?
1217
- kwargs = kwargs.key?(:include) || kwargs.key?(:exclude) ? statusargs.call : @revbuild || {}
1262
+ kwargs = kwargs.key?(:include) || kwargs.key?(:exclude) ? kw.call : @revbuild || {}
1218
1263
  case flag
1219
1264
  when :build
1220
- op = OptionPartition.new(opts, %w[ignore-submodules=b? ignored=b? untracked-files=b?], project: self)
1265
+ op = OptionPartition.new(opts, VAL_GIT[:revbuild].map { |key| "#{key}=b?" }, project: self)
1221
1266
  op.clear(append: true)
1222
1267
  args = op.to_a
1223
1268
  else
1224
- args = [
1225
- option('untracked-files', prefix: 'git') { |val| basic_option('untracked-files', val) },
1226
- option('ignore-submodules', prefix: 'git') { |val| basic_option('ignore-submodules', val) },
1227
- option('ignored', prefix: 'git') { |val| basic_option('ignored', val) }
1228
- ].compact
1269
+ args = parse_env('GIT_OPTIONS')
1270
+ .grep(/\A--#{Regexp.union(*VAL_GIT[:revbuild])}/)
1271
+ .concat(VAL_GIT[:revbuild].map { |key| option(key, prefix: 'git') { |val| basic_option(key, val) } })
1272
+ .compact
1273
+ OptionPartition.uniq!(args)
1229
1274
  end
1230
1275
  if (cur = workspace.rev_entry(name)) && cur['revision'] == sha && !env('REVBUILD_FORCE')
1231
1276
  files = status_digest(*args, **kwargs)
1232
1277
  if cur['files'].size == files.size && cur['files'].find { |key, val| files[key] != val }.nil?
1233
1278
  workspace.rev_timeutc(name, 'build') unless (since = workspace.rev_timesince(name, 'build'))
1234
1279
  if stdout?
1235
- puts log_message(Logger::INFO, name, 'no changes', subject: 'revbuild', hint: since && "#{since} ago")
1280
+ puts log_message(Logger::INFO, name, 'no changes', subject: 'revbuild', hint: ("#{since} ago" if since))
1236
1281
  end
1237
1282
  return
1238
1283
  end
1239
1284
  end
1240
1285
  start = time_epoch
1241
- build(@output, sync: sync, from: :'git:revbuild')
1286
+ build(*@output, sync: sync, from: :'git:revbuild')
1242
1287
  rescue StandardError => e
1243
1288
  print_error(e, pass: true)
1244
1289
  else
@@ -1346,7 +1391,7 @@ module Squared
1346
1391
  end
1347
1392
  end
1348
1393
 
1349
- def log!(flag, opts = [], range: [], index: [])
1394
+ def log!(flag, opts = [], range: [], index: [], grep: [])
1350
1395
  cmd, opts = git_session('log', opts: opts)
1351
1396
  op = OptionPartition.new(opts, collect_hash(OPT_GIT[:log]), cmd, project: self,
1352
1397
  no: collect_hash(OPT_GIT[:no][:log]),
@@ -1354,6 +1399,8 @@ module Squared
1354
1399
  case flag
1355
1400
  when :between, :contain
1356
1401
  op.add_quote(range.join(flag == :between ? '..' : '...'))
1402
+ when :grep
1403
+ op.merge(grep.map { |val| quote_option('grep', val) })
1357
1404
  else
1358
1405
  op.merge(index)
1359
1406
  end
@@ -1441,7 +1488,7 @@ module Squared
1441
1488
  cmd, opts = git_session('add', opts: opts)
1442
1489
  op = OptionPartition.new(opts, OPT_GIT[:add] + OPT_GIT[:log][:diff_context], cmd,
1443
1490
  project: self, no: OPT_GIT[:no][:add], first: matchpathspec)
1444
- op << '--verbose' if verbose
1491
+ op << '--verbose' unless silent?
1445
1492
  format = '%(if)%(HEAD)%(then)%(refname:short)...%(upstream:short)...%(upstream:track)%(end)'
1446
1493
  git_spawn 'fetch --no-tags --quiet'
1447
1494
  foreachref('heads', format: format).each do |line|
@@ -1460,7 +1507,6 @@ module Squared
1460
1507
  end
1461
1508
  origin = readline('Enter an upstream', force: true)
1462
1509
  end
1463
- raise_error ArgumentError, 'missing remote name', hint: origin unless origin.include?('/')
1464
1510
  upstream = true
1465
1511
  end
1466
1512
  break
@@ -1607,11 +1653,11 @@ module Squared
1607
1653
  next line if stdin?
1608
1654
 
1609
1655
  data = line.sub(/^\*\s+/, '').split(/\s+/)
1610
- a = sub_style(data[0], styles: theme[:inline])
1611
- b = sub_style(data[1], styles: theme[:extra])
1656
+ a = sub_style data[0], theme[:inline]
1657
+ b = sub_style data[1], theme[:extra]
1612
1658
  r = /\A(?:\[((?~\]\s))\]\s)?(.+)\z/m.match(data[2..-1].join(' '))
1613
1659
  if (r1 = r[1]) && r1 =~ /^(.+):(?: ([a-z]+) (\d+),)? ([a-z]+) (\d+)$/
1614
- write = ->(s1, s2) { "#{s1.capitalize.rjust(7)}: #{sub_style(s2, styles: theme[:warn])}" }
1660
+ write = ->(s1, s2) { "#{s1.capitalize.rjust(7)}: #{sub_style(s2, theme[:warn])}" }
1615
1661
  r1 = $1
1616
1662
  r2 = $2 && write.call($2, $3)
1617
1663
  r3 = write.call($4, $5)
@@ -1754,7 +1800,12 @@ module Squared
1754
1800
  def git(flag, opts = [])
1755
1801
  cmd, opts = git_session(flag, opts: opts)
1756
1802
  list = OPT_GIT[:git].fetch(flag, []) + OPT_GIT.fetch(flag, [])
1757
- list.concat(OPT_GIT[:log][:diff_context]) if flag == :add
1803
+ case flag
1804
+ when :add
1805
+ list.concat(OPT_GIT[:log][:diff_context])
1806
+ when :revert
1807
+ list.concat(VAL_GIT[:rebase][:send])
1808
+ end
1758
1809
  op = OptionPartition.new(opts, list, cmd, project: self, no: OPT_GIT[:no][flag], single: /\A\d+\z/,
1759
1810
  first: case flag
1760
1811
  when :blame, :revert then nil
@@ -1766,7 +1817,7 @@ module Squared
1766
1817
  op.append(basepath(op.remove_at(n)), delim: true)
1767
1818
  .clear
1768
1819
  when :revert
1769
- if VAL_GIT[:rebase][:send].any? { |val| op.arg?(val) }
1820
+ if op.arg?(*VAL_GIT[:rebase][:send])
1770
1821
  op.clear
1771
1822
  elsif op.empty?
1772
1823
  raise_error 'no commit target'
@@ -1782,7 +1833,7 @@ module Squared
1782
1833
  status_data.each do |a, b|
1783
1834
  next if b.strip.empty? || (!grep.empty? && grep.none? { |pat| pat.match?(a) })
1784
1835
 
1785
- out << "#{sub_style(b, styles: color(:red))} #{a}"
1836
+ out << "#{sub_style(b, color(:red))} #{a}"
1786
1837
  end
1787
1838
  end
1788
1839
  unless files.empty?
@@ -1911,7 +1962,7 @@ module Squared
1911
1962
  if loglevel
1912
1963
  log&.add loglevel, line
1913
1964
  else
1914
- sub&.each { |h| line = sub_style(line, **h) }
1965
+ sub&.each { |h| sub_style!(line, **h) }
1915
1966
  if banner
1916
1967
  out << line
1917
1968
  else
@@ -1940,7 +1991,7 @@ module Squared
1940
1991
  def choice_refs(msg, *type, format: nil, sort: '-creatordate', count: true, short: true, **kwargs)
1941
1992
  type << 'heads' if type.empty?
1942
1993
  unless format
1943
- format = +"%(refname#{short ? ':short' : ''})"
1994
+ format = +"%(refname#{':short' if short})"
1944
1995
  if type.include?('heads') || type.include?('tags')
1945
1996
  format += '%(if)%(HEAD)%(then) *%(end)'
1946
1997
  trim = /\s+\*\z/
@@ -2143,7 +2194,9 @@ module Squared
2143
2194
  end
2144
2195
 
2145
2196
  def repotrack(origin, branch, quote: true)
2146
- i = origin.index('/')
2197
+ unless origin && branch && (i = origin.index('/'))
2198
+ raise_error(ArgumentError, "missing #{origin ? 'branch' : 'remote'} name", hint: origin)
2199
+ end
2147
2200
  branch = "#{branch}:#{origin[i.succ..-1]}" unless origin.end_with?("/#{branch}")
2148
2201
  [origin[0..i.pred], branch].tap { |ret| ret.map! { |val| shell_quote(val) } if quote }
2149
2202
  end