squared 0.7.2 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9e8d3d41e090465c85e45088c984711f2a26f6ab2f38d56ed8b58658735f678
4
- data.tar.gz: 2ff93124747a950b6ac94424052268e4ab6b107e934a2fd16478ca03d74a5409
3
+ metadata.gz: 82923f41d47824239a45fb31f694e85d30c1cf0f73c099df00d2d7a210f6b156
4
+ data.tar.gz: e80edb54f73431248fb26d11ff53c5424ae791ef28b5a5ddcc3bb3f0da20622b
5
5
  SHA512:
6
- metadata.gz: 60b75a0d2d6c361ccf9341496b0b4e9e3a0599030ea6099f50a2819246111ff671a8f52cf583e91294593179949542f1e18814059c953007bbee528c1dbaa244
7
- data.tar.gz: c52d560aacea0d6279948db05d29c1a5b5c55a5d7fb2218f03d418122417a8ca3377a1b4af54238538d4d911c4827b6a2921b76001b161a6bfdd460e55dd13e5
6
+ metadata.gz: cbb9aaa755322f262c820b8f0cabb8e9bf6596e440e4d660311b5804b5c4f347c478c3bc2fddafdeddf4ff9643642da8c74445c118028e6ea904f59909232360
7
+ data.tar.gz: d0457af211645c310de59ae11cb693fbdb1c0fddd49989f805317dffb9db251693da9268fa2ad25b1739e94216b243521044502051ac8dbd111a65efdc31b1c0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.7.3] - 2026-03-11
4
+
5
+ ### Added
6
+
7
+ - Python command install action user for non-venv was implemented.
8
+ - Ruby command version can create .ruby-version in project directory.
9
+ - Ruby command reshim calls version manager to regenerate bin paths.
10
+ - Git command diff can be piped to an output file.
11
+
12
+ ### Changed
13
+
14
+ - Python command publish detects twine through the file system.
15
+ - Git revbuild can bypass checksum by project name using GIT_FORCE.
16
+ - Git internal data calls do not write to logs.
17
+ - Ruby method serve uses as default port 3000 due to Errno::EACCES.
18
+
19
+ ### Fixed
20
+
21
+ - Node command outdated using PNPM did not work in nested projects.
22
+
23
+ ## [0.6.11] - 2026-03-11
24
+
25
+ ### Changed
26
+
27
+ - Git internal data calls do not write to logs.
28
+
29
+ ## [0.5.22] - 2026-03-11
30
+
31
+ - Project base run command was not covered due to lack of type checking.
32
+
33
+ ## [0.4.36] - 2026-03-11
34
+
35
+ ### Added
36
+
37
+ - Python venv initialization installs setuptools when detected.
38
+ - Node task depend adds prod option flags when NODE_ENV=production.
39
+
40
+ ### Fixed
41
+
42
+ - OptionPartition methods with escape parameter were reordered.
43
+ - OptionPartition methods with quote parameter were revised.
44
+
45
+ ## [0.6.10] - 2025-02-23
46
+
47
+ ### Added
48
+
49
+ - Docker command image action [ls|rm|tag|save] can be filtered.
50
+ - Pip command options were updated to 26.1.
51
+
52
+ ### Changed
53
+
54
+ - Ruby property autodetect was converted into an accessor.
55
+ - Python property editable was converted into an accessor.
56
+
57
+ ### Fixed
58
+
59
+ - Gem command install did not respond to interactive prompt.
60
+
3
61
  ## [0.7.2] - 2026-02-09
4
62
 
5
63
  ### Added
@@ -1668,7 +1726,7 @@
1668
1726
  - Rake did not set original rakefile when calling itself.
1669
1727
  - Extended tasks were not associated to their supporting class method.
1670
1728
 
1671
- ## [0.1.0] - 2024-12-7
1729
+ ## [0.1.0] - 2024-12-07
1672
1730
 
1673
1731
  ### Added
1674
1732
 
@@ -1689,15 +1747,18 @@
1689
1747
  - Git pull did not display colors for diff bar chart.
1690
1748
  - Git commit did not fetch latest refs before submitting.
1691
1749
 
1692
- ## [0.0.12] - 2024-12-1
1750
+ ## [0.0.12] - 2024-12-01
1693
1751
 
1694
1752
  ### Added
1695
1753
 
1696
1754
  - Changelog was created.
1697
1755
 
1756
+ [0.7.3]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.3
1698
1757
  [0.7.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.2
1699
1758
  [0.7.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.1
1700
1759
  [0.7.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.0
1760
+ [0.6.11]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.11
1761
+ [0.6.10]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.10
1701
1762
  [0.6.9]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.9
1702
1763
  [0.6.8]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.8
1703
1764
  [0.6.7]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.7
@@ -1708,6 +1769,7 @@
1708
1769
  [0.6.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.2
1709
1770
  [0.6.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.1
1710
1771
  [0.6.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.0
1772
+ [0.5.22]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.22
1711
1773
  [0.5.21]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.21
1712
1774
  [0.5.20]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.20
1713
1775
  [0.5.19]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.19
@@ -1730,6 +1792,7 @@
1730
1792
  [0.5.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.2-ruby
1731
1793
  [0.5.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.1-ruby
1732
1794
  [0.5.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.0-ruby
1795
+ [0.4.36]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.36
1733
1796
  [0.4.35]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.35
1734
1797
  [0.4.34]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.34
1735
1798
  [0.4.33]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.33
data/README.md CHANGED
@@ -641,7 +641,7 @@ BANNER_${NAME}=0 #
641
641
  VERBOSE=0 # console output level
642
642
  VERBOSE_${NAME}=0 # 0,1,2,n
643
643
 
644
- REVBUILD_FORCE=1 # Rebuild all targets
644
+ REVBUILD_FORCE=1 # Rebuild all targets (GIT_FORCE)
645
645
  REVBUILD_FORCE_${NAME}=1 # Rebuild project
646
646
 
647
647
  PREREQS_${NAME}=build,copy # Class method name to invoke
@@ -749,12 +749,13 @@ docker build --no-cache --label=v1 --build-arg="NODE_TAG=24" --build-arg="RUBY_V
749
749
  | compose | run | VERSION=s |
750
750
  | compose | publish | TAG=s REGISTRY=s |
751
751
  | container | commit | REGISTRY=s PLATFORM=s DISABLE_CONTENT_TRUST=0,1 |
752
- | container | -run -create -exec | ALL=1 |
752
+ | container | -run -create -exec | ALL=1 FILTER=s |
753
753
  | | -update -commit | |
754
754
  | image | rm | Y=1 |
755
755
  | image | push | TAG=s REGISTRY=s |
756
756
  | image | -push | ALL=1 |
757
- | network | * | ALL=1 |
757
+ | image | -push -pull | FILTER=s |
758
+ | network | * | ALL=1 FILTER=s |
758
759
 
759
760
  ### asdf
760
761
 
@@ -10,7 +10,9 @@ module Squared
10
10
  private_constant :QUOTE_VALUE
11
11
 
12
12
  String.define_method(:stripquote) { sub(QUOTE_VALUE, '\2') }
13
- Array.define_method(:quote!) { |**kwargs| map { |s| Shell.shell_quote(s, **kwargs) } }
13
+ Array.define_method(:quote!) do |escape: false, **kwargs|
14
+ map { |s| escape && !Rake::Win32.windows? ? Shellwords.escape(s) : Shell.shell_quote(s, **kwargs) }
15
+ end
14
16
 
15
17
  module_function
16
18
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.7.2'
4
+ VERSION = '0.7.3'
5
5
  end
@@ -466,7 +466,7 @@ module Squared
466
466
  args[0] = instance_eval(&blk) || f
467
467
  return unless args.first
468
468
  end
469
- if args.all? { |val| val.is_a?(Array) }
469
+ if args.all?(Array)
470
470
  var = {}
471
471
  cmd = args.each_with_object([]) do |val, out|
472
472
  case val.first
@@ -782,19 +782,18 @@ module Squared
782
782
  ensure
783
783
  if dir
784
784
  remove_entry dir
785
- elsif delete && file&.exist?
785
+ elsif delete && file.exist?
786
786
  file.unlink
787
787
  end
788
788
  end
789
789
  end
790
790
 
791
- def asdf(flag, opts = [], version: nil)
791
+ def asdf(flag, opts = [], name: nil, version: nil, banner: true)
792
792
  return unless @asdf
793
793
 
794
794
  cmd = flag == :update ? session('asdf', 'plugin update') : session('asdf', flag)
795
- name = @asdf.first
795
+ name ||= @asdf.first
796
796
  legacy = @@asdf.version == 15
797
- banner = true
798
797
  case flag
799
798
  when :set
800
799
  u = has_value?(opts, 'u', 'home')
@@ -817,7 +816,7 @@ module Squared
817
816
  cmd << name
818
817
  banner = false if flag == :latest || flag == :where
819
818
  end
820
- success?(run(banner: banner, from: symjoin('asdf', flag)), flag == :set || flag == :reshim)
819
+ success?(run(banner: banner, from: symjoin('asdf', flag)), banner, flag == :set || flag == :reshim)
821
820
  end
822
821
 
823
822
  def first(key, *args, **kwargs, &blk)
@@ -1281,7 +1280,7 @@ module Squared
1281
1280
  print_error e
1282
1281
  end
1283
1282
  log[:progname] ||= @name
1284
- env('LOG_LEVEL', ignore: false) { |val| log[:level] = val.start_with?(/\d/) ? log_sym(val.to_i) : val }
1283
+ env('LOG_LEVEL', ignore: false) { |s| log[:level] = s.start_with?(/\d/) ? log_sym(s.to_i) : s }
1285
1284
  log.delete(:file)
1286
1285
  @log = [file, log]
1287
1286
  end
@@ -1460,17 +1459,17 @@ module Squared
1460
1459
  s += "#{indent || (last && data[final].last == kwargs[:context]) ? ' ' : a} "
1461
1460
  k += 1
1462
1461
  end
1463
- s += "#{j ? d : c}#{b * 3} #{tag.call(proj)}"
1462
+ s + "#{j ? d : c}#{b * 3} #{tag.call(proj)}"
1464
1463
  end
1465
1464
  end
1466
1465
  if order
1467
1466
  n = order.size
1468
1467
  order[name] ||= if proj.parent
1469
- if order[s = proj.parent.name]
1470
- order[s] += 1
1468
+ if order[key = proj.parent.name]
1469
+ order[key] += 1
1471
1470
  n.pred
1472
1471
  else
1473
- order[s] = n.succ
1472
+ order[key] = n.succ
1474
1473
  n
1475
1474
  end
1476
1475
  else
@@ -2044,10 +2043,12 @@ module Squared
2044
2043
  [shell_bin(a), b].compact.join(' ')
2045
2044
  end
2046
2045
 
2047
- def parse_json(val, kind: Hash, hint: nil)
2046
+ def parse_json(val, kind: Hash, key: nil, hint: nil, &blk)
2048
2047
  ret = JSON.parse(val)
2049
2048
  raise_error 'invalid JSON'.subhint(kind.name), val, hint: hint if kind && !ret.is_a?(kind)
2050
- ret
2049
+ return ret unless key
2050
+
2051
+ block_given? ? ret.fetch(key, &blk) : ret[key]
2051
2052
  rescue => e
2052
2053
  print_error(kind ? Logger::ERROR : Logger::INFO, e, subject: name)
2053
2054
  end
@@ -2421,7 +2422,7 @@ module Squared
2421
2422
  ret = []
2422
2423
  if data[:command]
2423
2424
  ret[0] = data[:command]
2424
- ret[1] = data[:opts] unless diso
2425
+ ret[1] = data[:opts] unless noopt
2425
2426
  ret[3] = data[:args]
2426
2427
  elsif data[:script]
2427
2428
  ret[1] = data[:script]
@@ -2430,7 +2431,7 @@ module Squared
2430
2431
  else
2431
2432
  ret[0] = false
2432
2433
  end
2433
- ret[2] = data[:env] unless dise
2434
+ ret[2] = data[:env] unless noenv
2434
2435
  ret
2435
2436
  end
2436
2437
  case global
@@ -2445,7 +2446,7 @@ module Squared
2445
2446
  when Hash
2446
2447
  @output = parse.call(data)
2447
2448
  when Enumerable
2448
- @output = if cmd.all? { |data| data.is_a?(Hash) }
2449
+ @output = if cmd.all?(Hash)
2449
2450
  noopt = false
2450
2451
  noenv = false
2451
2452
  cmd.map { |data| parse.call(data) }
@@ -72,8 +72,8 @@ module Squared
72
72
  }.freeze,
73
73
  network: {
74
74
  connect: %w[alias=b driver-opt=q gw-priority=n ip=b ip6=q link=b link-local-ip=q].freeze,
75
- create: %w[attachable config-only gateway ingress internal ipv4 ipv6 aux-address=q config-from=b d|driver=b
76
- ip-range=q ipam-driver=b ipam-opt=q label=q o|opt=q scope=b subnet=q].freeze,
75
+ create: %w[attachable config-only gateway=q ingress internal ipv4 ipv6 aux-address=q config-from=b
76
+ d|driver=b ip-range=q ipam-driver=b ipam-opt=q label=q o|opt=q scope=b subnet=q].freeze,
77
77
  disconnect: %w[f|force].freeze
78
78
  }.freeze
79
79
  }.freeze
@@ -128,7 +128,7 @@ module Squared
128
128
  self.global = nil
129
129
  return unless dockerfile(kwargs[:file]).exist?
130
130
 
131
- self.tag = kwargs[:tag] || tagname("#{@project}:#{@version || 'latest'}")
131
+ @tag = kwargs[:tag] || tagname("#{@project}:#{@version || 'latest'}")
132
132
  @context = kwargs[:context]
133
133
  @mounts = mounts
134
134
  @secrets = kwargs[:secrets]
@@ -298,14 +298,18 @@ module Squared
298
298
  end
299
299
  else
300
300
  format_desc(action, flag, case flag
301
- when :rm, :save then 'id*,opts*'
302
- when :tag then 'version?'
301
+ when :rm, :save then 'id,opts*'
302
+ when :tag then 'version'
303
303
  else 'opts*,args*'
304
- end)
304
+ end, before: 'pattern?')
305
305
  task flag do |_, args|
306
306
  args = args.to_a
307
+ n = args.size
308
+ if (n > 1 || (flag == :ls && n > 0)) && OptionPartition.pattern?(args.first)
309
+ filter = args.shift
310
+ end
307
311
  if !args.empty? || flag == :ls
308
- image flag, args
312
+ image(flag, args, filter: filter)
309
313
  else
310
314
  choice_command flag
311
315
  end
@@ -531,7 +535,7 @@ module Squared
531
535
  return unless confirm_command(cmd.to_s, title: from, target: id, as: latest)
532
536
 
533
537
  registry = option('registry') || @registry
534
- run(from: from, exception: registry.nil? ? exception : true)
538
+ run(from: from, exception: registry.nil? ? exception? : true)
535
539
  return unless registry
536
540
 
537
541
  opts = []
@@ -556,7 +560,7 @@ module Squared
556
560
  run(from: from)
557
561
  end
558
562
 
559
- def image(flag, opts = [], sync: true, id: nil, registry: nil)
563
+ def image(flag, opts = [], sync: true, id: nil, registry: nil, filter: nil)
560
564
  cmd, opts = docker_session('image', flag, opts: opts)
561
565
  op = OptionPartition.new(opts, OPT_DOCKER[:image].fetch(flag, []), cmd, project: self)
562
566
  exception = exception?
@@ -574,7 +578,7 @@ module Squared
574
578
  opts.delete(val)
575
579
  break
576
580
  end
577
- list_image(:run, from: from) do |val|
581
+ list_image(:run, filter: filter, from: from) do |val|
578
582
  container(:run, if name
579
583
  opts.dup << "name=#{index == 0 ? name : "#{name}-#{index}"}"
580
584
  else
@@ -588,7 +592,7 @@ module Squared
588
592
  when :rm
589
593
  unless id
590
594
  if op.empty?
591
- list_image(:rm, from: from) { |val| image(:rm, opts, sync: sync, id: val) }
595
+ list_image(:rm, filter: filter, from: from) { |val| image(:rm, opts, sync: sync, id: val) }
592
596
  else
593
597
  op.each { |val| run(cmd.temp(val), sync: sync, from: from) }
594
598
  end
@@ -600,13 +604,16 @@ module Squared
600
604
  banner = false
601
605
  end
602
606
  when :tag, :save
603
- list_image(flag, from: from) do |val|
607
+ found = false
608
+ list_image(flag, filter: filter, from: from) do |val|
604
609
  op << val
605
- next unless flag == :tag
606
-
607
- op << tagname("#{project}:#{op.first}")
608
- break
610
+ found = true
611
+ if flag == :tag
612
+ op << tagname("#{project}:#{op.first}")
613
+ break
614
+ end
609
615
  end
616
+ raise_error ArgumentError, 'target not specified', hint: flag unless found
610
617
  when :pull
611
618
  if !id
612
619
  id = tagmain
@@ -795,12 +802,20 @@ module Squared
795
802
  [cmd, status, no]
796
803
  end
797
804
 
798
- def list_image(flag, cmd = docker_output('image ls -a'), hint: nil, no: true, from: nil)
805
+ def list_image(flag, cmd = docker_output('image ls -a'), filter: nil, hint: nil, no: true, from: nil)
799
806
  pwd_set(from: from) do
800
807
  index = 1
801
808
  all = option('all', prefix: 'docker')
802
809
  y = from == :'image:rm' && option('y', prefix: 'docker')
803
- pat = /\b(?:#{dnsname(name)}|#{tagname(project)}|#{tagmain.split(':', 2).first})\b/
810
+ filter = env('DOCKER_FILTER', filter).to_s
811
+ pat = if OptionPartition.pattern?(filter)
812
+ Regexp.new(filter)
813
+ elsif filter.match?(/[:_-]$/)
814
+ /\b#{Regexp.escape(filter)}/
815
+ else
816
+ filter = filter.empty? ? '(?:[:_-]|$)' : "[:_-]#{filter}"
817
+ /\b(?:#{dnsname(name)}|#{tagname(project)}|#{tagmain.split(':', 2).first})#{filter}/
818
+ end
804
819
  IO.popen(cmd.temp('--format=json')).each do |line|
805
820
  data = JSON.parse(line)
806
821
  id = data['ID']
@@ -436,7 +436,7 @@ module Squared
436
436
  end
437
437
  if squash
438
438
  found = false
439
- git_spawn(git_output('log --format=%h'), stdout: false).each do |val|
439
+ git_spawn('log --format=%h', stdout: false).each do |val|
440
440
  if found
441
441
  squash = val.chomp
442
442
  break
@@ -1320,7 +1320,12 @@ module Squared
1320
1320
  OptionPartition.uniq!(args)
1321
1321
  end
1322
1322
  run_p(*Array(kwargs[:before]), sync: sync, from: :revbuild) if kwargs[:before]
1323
- if (cur = workspace.rev_entry(name)) && cur['revision'] == sha && !env('REVBUILD_FORCE')
1323
+ force = if (force = env('REVBUILD_FORCE', strict: true))
1324
+ force != '0' && force != 'false'
1325
+ elsif (force = ENV['GIT_FORCE'] || ENV['REVBUILD_FORCE'])
1326
+ split_escape(force).any? { |val| val == '1' || val == 'true' || val == name }
1327
+ end
1328
+ if !force && (cur = workspace.rev_entry(name)) && cur['revision'] == sha
1324
1329
  files = status_digest(*args, **kwargs)
1325
1330
  if cur['files'].size == files.size && cur['files'].find { |key, val| files[key] != val }.nil?
1326
1331
  workspace.rev_timeutc(name, 'build') unless (since = workspace.rev_timesince(name, 'build'))
@@ -1475,14 +1480,6 @@ module Squared
1475
1480
  op << '--no-index'
1476
1481
  patch = refs.pop
1477
1482
  append_pathspec(refs, parent: true)
1478
- if patch
1479
- patch = basepath patch
1480
- exit 1 if patch.exist? && !confirm_basic('Overwrite?', patch)
1481
- op << '>' << shell_quote(patch)
1482
- source(banner: false)
1483
- puts patch.read if patch.exist? && (stdin? || verbose?)
1484
- return
1485
- end
1486
1483
  else
1487
1484
  op << '--merge-base' if option('merge-base')
1488
1485
  case flag
@@ -1504,9 +1501,22 @@ module Squared
1504
1501
  op << "HEAD~#{n}"
1505
1502
  end
1506
1503
  end
1504
+ if (n = op.index('>'))
1505
+ patch = op.slice!(n, 2)[1]
1506
+ elsif !op.exist?(op.last)
1507
+ patch ||= op.pop
1508
+ end
1507
1509
  append_pathspec op.extras
1508
1510
  end
1509
- source(exception: op.arg?('exit-code'))
1511
+ if patch
1512
+ patch = basepath patch.delete_prefix('>')
1513
+ exit 1 if patch.exist? && !confirm_basic('Overwrite?', patch)
1514
+ op << '>' << shell_quote(patch)
1515
+ source(banner: false)
1516
+ puts patch.read if patch.exist? && (stdin? || verbose?)
1517
+ else
1518
+ source(exception: op.arg?('exit-code'))
1519
+ end
1510
1520
  end
1511
1521
 
1512
1522
  def commit(flag, opts = [], refs: [], ref: nil, squash: nil, pick: nil, message: nil, pass: false)
@@ -1962,23 +1972,23 @@ module Squared
1962
1972
  if io && banner == false
1963
1973
  from = nil
1964
1974
  banner = nil
1975
+ args = false
1965
1976
  else
1966
- if banner
1967
- banner = nil unless banner? && !multiple
1968
- args = true
1969
- end
1970
1977
  if from == false
1971
1978
  from = nil
1972
1979
  elsif !from && cmd.respond_to?(:drop)
1973
1980
  from = cmd.drop(1).find { |val| val.match?(/\A[a-z]{1,2}[a-z-]*\z/) }
1974
1981
  from &&= symjoin 'git', from
1975
1982
  end
1976
- banner &&= cmd.temp { |val| val.start_with?(/--(work-tree|git-dir)/) } if cmd.respond_to?(:temp)
1983
+ if banner
1984
+ banner = cmd.temp { |val| val.start_with?(/--(work-tree|git-dir)/) } if cmd.respond_to?(:temp)
1985
+ args = true
1986
+ end
1977
1987
  end
1978
1988
  timeout = session_timeout cmd if timeout.nil?
1979
1989
  cmd = session_done cmd
1980
- log&.info cmd
1981
- banner = if banner
1990
+ log&.info cmd unless args == false
1991
+ banner = if banner && banner? && !multiple
1982
1992
  format_banner(banner.is_a?(String) ? banner : cmd, hint: hint, strip: true)
1983
1993
  end
1984
1994
  on :first, from
@@ -2164,9 +2174,7 @@ module Squared
2164
2174
 
2165
2175
  def append_message(val = nil, target: @session)
2166
2176
  val = messageopt if val.to_s.empty?
2167
- return unless val
2168
-
2169
- target << quote_option('message', val)
2177
+ target << quote_option('message', val) if val
2170
2178
  end
2171
2179
 
2172
2180
  def append_head(val = nil, target: @session)
@@ -5,7 +5,7 @@ module Squared
5
5
  module Project
6
6
  class Node < Git
7
7
  OPT_NPM = {
8
- common: %w[dry-run=!? loglevel=b include-workspace-root=!? workspaces=!? w|workspace=v].freeze,
8
+ common: %w[dry-run=!? force=!? loglevel=b include-workspace-root=!? workspaces=!? w|workspace=v].freeze,
9
9
  install: %w[package-lock-only=!? prefer-dedupe=!? E|save-exact=!? before=q cpu=b libc=b os=b].freeze,
10
10
  install_a: %w[audit=! bin-links=! foreground-scripts=!? fund=! ignore-scripts=!? install-links=!?
11
11
  package-lock=! strict-peer-deps=!? include=b install-strategy=b omit=b].freeze,
@@ -552,31 +552,36 @@ module Squared
552
552
  end
553
553
  yarn = dependtype(:yarn)
554
554
  if yarn > 0
555
- cmd = session('yarn', flag || 'install')
556
- append_loglevel
557
- if yarn == 1
558
- cmd << '--ignore-engines' if option('ignore-engines')
559
- cmd << '--ignore-scripts' if option('ignore-scripts')
560
- cmd << '--force' if option('force')
555
+ if !flag && yarn > 1 && prod?
556
+ cmd = session 'yarn', 'workspaces focus --all --production'
561
557
  else
562
- cmd << '--mode=skip-build' if option('ignore-scripts')
563
- cmd << '--check-cache' if !flag && option('force')
564
- end
565
- if nolockfile?('yarn')
566
- cmd << '--no-lockfile'
567
- elsif option('ci')
558
+ cmd = session('yarn', flag || 'install')
568
559
  if yarn == 1
569
- cmd << '--frozen-lockfile'
570
- elsif !flag
571
- cmd << '--immutable' << '--refresh-lockfile'
560
+ cmd << '--production' if prod?
561
+ cmd << '--ignore-engines' if option('ignore-engines')
562
+ cmd << '--ignore-scripts' if option('ignore-scripts')
563
+ cmd << '--force' if option('force')
564
+ else
565
+ cmd << '--mode=skip-build' if option('ignore-scripts')
566
+ cmd << '--check-cache' if !flag && option('force')
567
+ end
568
+ if nolockfile?('yarn')
569
+ cmd << '--no-lockfile'
570
+ elsif option('ci')
571
+ if yarn == 1
572
+ cmd << '--frozen-lockfile'
573
+ elsif !flag
574
+ cmd << '--immutable' << '--refresh-lockfile'
575
+ end
576
+ end
577
+ if add
578
+ cmd << '-W' if yarn == 1 && option('w', 'ignore-workspace-root-check', notequals: '0')
579
+ rm.call(cmd)
580
+ om.call(cmd)
581
+ cmd << '--exact' if exact
572
582
  end
573
583
  end
574
- if add
575
- cmd << '-W' if yarn == 1 && option('w', 'ignore-workspace-root-check', notequals: '0')
576
- rm.call(cmd)
577
- om.call(cmd)
578
- cmd << '--exact' if exact
579
- end
584
+ append_loglevel
580
585
  elsif pnpm?
581
586
  cmd = session('pnpm', flag || 'install')
582
587
  append_nocolor
@@ -587,6 +592,7 @@ module Squared
587
592
  cmd << '--save-exact' if exact
588
593
  option('allow-build') { |val| cmd << quote_option('allow-build', val) }
589
594
  else
595
+ cmd << '--prod' if prod?
590
596
  append_platform
591
597
  end
592
598
  option('public-hoist-pattern') do |val|
@@ -611,6 +617,8 @@ module Squared
611
617
  if omit
612
618
  cmd << "--omit=#{save || omit}"
613
619
  save = nil
620
+ elsif !add && prod?
621
+ cmd << '--include=prod'
614
622
  end
615
623
  unless ci
616
624
  if add
@@ -634,7 +642,7 @@ module Squared
634
642
  end
635
643
 
636
644
  def outdated(flag = nil, opts = [], sync: invoked_sync?('outdated', flag))
637
- cmd = session(pnpm? ? 'pnpm' : 'npm', 'outdated')
645
+ cmd = session(pnpm? && exist?('pnpm-lock.yaml') ? 'pnpm' : 'npm', 'outdated')
638
646
  dryrun = has_value?(opts, 'd', 'dry-run') || dryrun?
639
647
  unless dryrun
640
648
  log.info cmd.to_s