kettle-dev 3.0.0 → 3.0.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: c7cdd1aace2e06deda5e6bb04aa3b2e6ef67408f0521c8d0ed6a8fa27fad23be
4
- data.tar.gz: e23d202928cd64875dffdb94bb426e0925e2033a7b07ba36b154eba7c83175d8
3
+ metadata.gz: 335bd9651ff7bbe5381c8e050a26f070c6accd8054ab581226ba3355c8a4aa6e
4
+ data.tar.gz: 7f59238412adde48ba5f2b524b08e4ce77a5348c81d0984e44013e6ce905b2dc
5
5
  SHA512:
6
- metadata.gz: a6c052d533011b2e59762247ee8cb7d8f794e2383720dc7d589beb1643e8086451f5f2922f5b6f77b3d46cebb4f657c07d290ab3c0146e99e2a9196149ce1002
7
- data.tar.gz: 6a38aaf07275a14e588d8e03ab35f8c208755a78c5ac222328688fea61eafde8770bd826abedc8ae91742723dcf69ae09b97782a9eec97e75ebeb380422e6ba2
6
+ metadata.gz: 94e3d356b963078c8dd46d50d0f2b7ed92f656327bd3f766618617b56172ae0051dc32f6469cfd5c9faf539e00a4bbdf123947dd8febbd10c34172f51a2efc2d
7
+ data.tar.gz: d2eee5766a478c4846f05969ac4fcbf4614793740911c029219d85fb446fd308f9c376c5fa8d68edbdc71bd144dba09a1ad927c5915278c7933d0fc50ac74dca
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,19 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [3.0.1] - 2026-08-10
34
+
35
+ - TAG: [v3.0.1][3.0.1t]
36
+ - COVERAGE: 91.87% -- 5602/6098 lines in 47 files
37
+ - BRANCH COVERAGE: 76.29% -- 2117/2775 branches in 47 files
38
+ - 50.64% documented
39
+
40
+ ### Fixed
41
+
42
+ - Run 1Password authorization keepalives through the interactive terminal so release prompts remain visible.
43
+
44
+ - Re-normalize release lockfiles after release tasks before commit and CI validation.
45
+
33
46
  ## [3.0.0] - 2026-08-09
34
47
 
35
48
  - TAG: [v3.0.0][3.0.0t]
@@ -3401,7 +3414,9 @@ Please file a bug if you notice a violation of semantic versioning.
3401
3414
  - Selecting will run the selected workflow via `act`
3402
3415
  - This may move to its own gem in the future.
3403
3416
 
3404
- [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.0...HEAD
3417
+ [Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.1...HEAD
3418
+ [3.0.1]: https://github.com/kettle-dev/kettle-dev/compare/v3.0.0...v3.0.1
3419
+ [3.0.1t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.1
3405
3420
  [3.0.0]: https://github.com/kettle-dev/kettle-dev/compare/v2.5.28...v3.0.0
3406
3421
  [3.0.0t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.0.0
3407
3422
  [2.5.28]: https://github.com/kettle-dev/kettle-dev/compare/v2.5.27...v2.5.28
data/README.md CHANGED
@@ -1007,7 +1007,7 @@ Thanks for RTFM. ☺️
1007
1007
  [📌gitmoji]: https://gitmoji.dev
1008
1008
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
1009
1009
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
1010
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.069-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1010
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-6.098-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
1011
1011
  [🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
1012
1012
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
1013
1013
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
@@ -1,39 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "open3"
4
+ require "shellwords"
4
5
 
5
6
  module Kettle
6
7
  module Dev
7
8
  class InteractiveReleaseCommand
8
- def initialize(secrets_provider:, input: $stdin, output: $stdout, error: $stderr, secret_event_handler: nil)
9
+ def initialize(secrets_provider:, input: $stdin, output: $stdout, error: $stderr, secret_event_handler: nil, forward_stdin: false)
9
10
  @secrets_provider = secrets_provider
10
11
  @input = input
11
12
  @output = output
12
13
  @error = error
13
14
  @secret_event_handler = secret_event_handler
15
+ @forward_stdin = forward_stdin
14
16
  @gem_signing_passphrase = nil
15
17
  end
16
18
 
17
19
  def call(env, cmd)
18
- return call_with_pty(env, cmd) if pty_available?
20
+ call_argv(env, Shellwords.split(cmd.to_s))
21
+ end
22
+
23
+ def call_argv(env, argv)
24
+ return call_with_pty(env, argv) if pty_available?
19
25
 
20
- call_with_open3(env, cmd)
26
+ call_with_open3(env, argv)
21
27
  end
22
28
 
23
29
  private
24
30
 
25
31
  attr_reader :secrets_provider, :secret_event_handler
26
32
 
27
- def call_with_pty(env, cmd)
33
+ def call_with_pty(env, argv)
28
34
  stdout_str = +""
35
+ prompt_buffer = +""
29
36
  status = nil
30
- PTY.spawn(env, cmd) do |output, input, pid|
37
+ PTY.spawn(env, *argv) do |output, input, pid|
31
38
  begin
32
39
  loop do
33
- chunk = output.readpartial(1024)
34
- stdout_str << chunk
35
- @output.print(chunk)
36
- handle_prompt(input, chunk)
40
+ readers = [output]
41
+ readers << @input if @forward_stdin && @input.tty?
42
+ IO.select(readers).first.each do |reader|
43
+ if reader.equal?(@input)
44
+ input.write(@input.readpartial(1024))
45
+ else
46
+ chunk = output.readpartial(1024)
47
+ stdout_str << chunk
48
+ @output.print(chunk)
49
+ prompt_buffer = handle_prompt(input, chunk, prompt_buffer: prompt_buffer)
50
+ end
51
+ end
37
52
  end
38
53
  rescue Errno::EIO
39
54
  # PTY raises EIO when the child process exits after closing the slave.
@@ -47,27 +62,33 @@ module Kettle
47
62
  [stdout_str, "", status]
48
63
  end
49
64
 
50
- def call_with_open3(env, cmd)
65
+ def call_with_open3(env, argv)
51
66
  stdout_str = +""
52
67
  stderr_str = +""
68
+ prompt_buffer = +""
53
69
  status = nil
54
- Open3.popen3(env, cmd) do |input, output, error, wait_thread|
70
+ Open3.popen3(env, *argv) do |input, output, error, wait_thread|
55
71
  readers = [output, error]
72
+ readers << @input if @forward_stdin && @input.tty?
56
73
  until readers.empty?
57
74
  ready = IO.select(readers)
58
75
  ready.first.each do |reader|
59
- begin
60
- chunk = reader.readpartial(1024)
61
- if reader.equal?(output)
62
- stdout_str << chunk
63
- @output.print(chunk)
64
- else
65
- stderr_str << chunk
66
- @error.print(chunk)
76
+ if reader.equal?(@input)
77
+ input.write(@input.readpartial(1024))
78
+ else
79
+ begin
80
+ chunk = reader.readpartial(1024)
81
+ if reader.equal?(output)
82
+ stdout_str << chunk
83
+ @output.print(chunk)
84
+ else
85
+ stderr_str << chunk
86
+ @error.print(chunk)
87
+ end
88
+ prompt_buffer = handle_prompt(input, chunk, prompt_buffer: prompt_buffer)
89
+ rescue EOFError
90
+ readers.delete(reader)
67
91
  end
68
- handle_prompt(input, chunk)
69
- rescue EOFError
70
- readers.delete(reader)
71
92
  end
72
93
  end
73
94
  end
@@ -76,13 +97,21 @@ module Kettle
76
97
  [stdout_str, stderr_str, status]
77
98
  end
78
99
 
79
- def handle_prompt(input, chunk)
80
- if otp_prompt?(chunk)
81
- write_secret(input, label: "RubyGems MFA code", source: "rubygems_otp") { secrets_provider.rubygems_otp } if otp_response_prompt?(chunk)
82
- return
100
+ def handle_prompt(input, chunk, prompt_buffer: nil)
101
+ prompt_buffer = prompt_buffer.to_s.dup
102
+ prompt_buffer << chunk.to_s
103
+ prompt_buffer = prompt_buffer.byteslice([prompt_buffer.bytesize - 4096, 0].max, 4096).to_s
104
+
105
+ if otp_prompt?(prompt_buffer)
106
+ if otp_response_prompt?(prompt_buffer)
107
+ write_secret(input, label: "RubyGems MFA code", source: "rubygems_otp") { secrets_provider.rubygems_otp }
108
+ return +""
109
+ end
110
+ return prompt_buffer
83
111
  end
84
112
 
85
- write_secret(input, label: "gem signing passphrase", source: "gem_signing_passphrase") { gem_signing_passphrase } if signing_password_prompt?(chunk)
113
+ write_secret(input, label: "gem signing passphrase", source: "gem_signing_passphrase") { gem_signing_passphrase } if signing_password_prompt?(prompt_buffer)
114
+ prompt_buffer
86
115
  end
87
116
 
88
117
  def gem_signing_passphrase
@@ -622,7 +622,10 @@ module Kettle
622
622
  end
623
623
 
624
624
  def prepare_release_lockfiles_for_commit!
625
- reset_release_lockfiles!(stage: "before release prep commit") unless @release_lockfiles_reset_for_release_tasks
625
+ # Release setup and documentation tasks can re-materialize local PATH
626
+ # sources in the parent development bundle after the preflight reset.
627
+ # Always normalize again at the commit boundary.
628
+ reset_release_lockfiles!(stage: "before release prep commit")
626
629
  validate_release_lockfiles!(stage: "before release prep commit")
627
630
  end
628
631
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "open3"
4
+ require "kettle/dev/interactive_release_command"
4
5
  require "kettle/dev/release_notifier"
5
6
 
6
7
  module Kettle
@@ -73,7 +74,7 @@ module Kettle
73
74
  argv = [op_cli, "account", "get"]
74
75
  account = string_config("account")
75
76
  argv.concat(["--account", account]) unless account.empty?
76
- run_op(argv, purpose: "authorization keepalive", elapsed: elapsed)
77
+ run_op(argv, purpose: "authorization keepalive", elapsed: elapsed, interactive: true)
77
78
  true
78
79
  end
79
80
 
@@ -112,9 +113,11 @@ module Kettle
112
113
  required_config("cli")
113
114
  end
114
115
 
115
- def run_op(argv, purpose:, elapsed: nil)
116
+ def run_op(argv, purpose:, elapsed: nil, interactive: false)
116
117
  elapsed_suffix = elapsed.to_s.empty? ? "" : " (elapsed #{elapsed})"
117
118
  Kettle::Dev::ReleaseNotifier.alert("1Password #{purpose} lookup starting#{elapsed_suffix}; watch for authorization prompt.")
119
+ return run_interactive_op(argv, purpose: purpose) if interactive
120
+
118
121
  stdout, stderr, status = Open3.capture3(*argv)
119
122
  return stdout.to_s.strip if status.success? && !stdout.to_s.strip.empty?
120
123
 
@@ -125,6 +128,23 @@ module Kettle
125
128
  raise Kettle::Dev::Error, "1Password CLI executable #{argv.first.inspect} was not found"
126
129
  end
127
130
 
131
+ def run_interactive_op(argv, purpose:)
132
+ _stdout, stderr, status = Kettle::Dev::InteractiveReleaseCommand.new(
133
+ secrets_provider: Provider.new,
134
+ input: $stdin,
135
+ output: $stdout,
136
+ error: $stderr,
137
+ forward_stdin: true
138
+ ).call_argv({}, argv)
139
+ return if status.success?
140
+
141
+ details = stderr.to_s.strip
142
+ details = "op exited #{status.exitstatus}" if details.empty?
143
+ raise Kettle::Dev::Error, "1Password #{purpose} lookup failed: #{details}"
144
+ rescue Errno::ENOENT
145
+ raise Kettle::Dev::Error, "1Password CLI executable #{argv.first.inspect} was not found"
146
+ end
147
+
128
148
  def required_config(key)
129
149
  value = string_config(key)
130
150
  raise Kettle::Dev::Error, "1Password release secrets require #{key}" if value.empty?
@@ -5,7 +5,7 @@ module Kettle
5
5
  # Version namespace for this gem.
6
6
  module Version
7
7
  # Current gem version.
8
- VERSION = "3.0.0"
8
+ VERSION = "3.0.1"
9
9
  end
10
10
  # Current gem version exposed at the traditional constant location.
11
11
  VERSION = Version::VERSION # Traditional Constant Location
data.tar.gz.sig CHANGED
@@ -1,4 +1,4 @@
1
- b"ݽ�� ����}$`/'`���W����,�YވvC8 P���x�
2
- Gk��3o@�[51?��>Zm_�1Xx:� y�|C�H.Bj�3���E��Y���xj�c��呙@4@���6����
3
- ���.���ne��D r�׽��؞Ŕ��x�P����s�J�o���=��l��>������LC� :a@���0m<�/��$�y͔� ��� ��)��T��Y~��";�Ւ���,�zZ�����0��x������$�����o�Oυ��tU���I��5RMK�� �Q}>�[�<�%D��7`���&{IZtN sCJ*1�z@&�,�2�~o�8�ɍ
4
- e$6���Ľf'� \
1
+ S+|I"{w�� Vtnhl4eL;�c��X�F׏wH�(Y�2C�1[���{��[���!����C�䄮N�\��;�� ^DZ)_��q�[��mSP8��di�U�Z�^GG6F|�M������]�]%,��T�I* �@��"xЂ <�dV��k��NgvH'l�闞�Q�F��ə?ȬU0z(�O@
2
+ �RE+��qsU[���?�c5ɰ1N-
3
+ -��A���i#;'�k�f���5�h�B���-��� ��<���rp���������xj<g�X�+W��4dt4l�����bX�Y ��\��m�"b%Nz{ ��grY ]�`��1�n�z�p$+��
4
+ T�\���B��L!;��Z��<a��]J�y�M�k���j�
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kettle-dev
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter H. Boling
@@ -400,10 +400,10 @@ licenses:
400
400
  - AGPL-3.0-only
401
401
  metadata:
402
402
  homepage_uri: https://kettle-dev.galtzo.com
403
- source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.0.0
404
- changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.0/CHANGELOG.md
403
+ source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.0.1
404
+ changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.0.1/CHANGELOG.md
405
405
  bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
406
- documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.0.0
406
+ documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.0.1
407
407
  funding_uri: https://github.com/sponsors/pboling
408
408
  wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
409
409
  news_uri: https://www.railsbling.com/tags/kettle-dev
metadata.gz.sig CHANGED
Binary file