specguard-ruby 0.3.18 → 0.3.19

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: 5df698ea1b4e7a3c769128feb51bb7dbf46e0b6f5eee5c74cb4d290ca9d04d11
4
- data.tar.gz: 247e9962c2bf44d06511a161ed19bcb4168aeb48476f535fadacf8da905f583b
3
+ metadata.gz: 50dc4bf3c9b0b9c563cdff66cd57f43fe24b17bde2177c700fed2221a3e69f90
4
+ data.tar.gz: a95f8836a1121b5e6d71cf628290915e5fbf38c781c9c610a723bab5896e945d
5
5
  SHA512:
6
- metadata.gz: c6befb4eb61b41cce78a5de0ddccd7eb09cee9cc7d8e58b429a43f95ad2113e965eb627f8225462b8f47ef2015e502eaa69bfc6b4f09f620bcedd0c7c8345520
7
- data.tar.gz: 3a8df006b85851e865caff948b8cfc9d98c66abf39a8e5eb7b15f9860e428f27d07aab66b5a7c7ff24403fe1e806b36b70895329614128f43f801001b53d7a38
6
+ metadata.gz: 04b0bd2e271bccc2090f609013c241c0ebaa2bea877601611b4515359f0a8ed31079d2823d332d8a1b89ba31985aa3eca1a4996e6c115e5107902d97b81f26d4
7
+ data.tar.gz: f83b0134fae75d22af014af313c0b74108362a6671fab1a6d62f428739ecdabd585f553c7536a0833c4ef138fd25f267a484db87f684970468fad5e4a05866f3
@@ -40,6 +40,29 @@ module SpecGuard
40
40
  # caught. Ctrl-C must stay Ctrl-C; mapping it to "the linter is broken"
41
41
  # would be its own small lie.
42
42
  #
43
+ # `Errno::EPIPE` is the same lie arriving by the shell's ordinary
44
+ # end-of-pipe. `specguard-lint … | head`, a quitting pager, a CI log
45
+ # tailer that stopped reading — none of these are the linter failing, and
46
+ # the run itself is correct: the verdict was computed and the reader
47
+ # simply stopped listening. Left in the bands it fabricates a 2 two
48
+ # different ways (SPGD-1288): a mid-report EPIPE reaches the backstop and
49
+ # reads as `internal error:`; and because `Open3.capture3` flushes THIS
50
+ # process's buffered stdout while setting up the validator child, the
51
+ # same EPIPE can surface from inside {ValidatorBackend::Runner#run},
52
+ # whose `SystemCallError` rescue — written for a child that cannot
53
+ # execute — re-wraps it as a `ValidatorError`, accusing the configured
54
+ # backend of a fault that does not exist. {Runner#run} passes the EPIPE
55
+ # through as itself, and the rescue below it here, placed ahead of both
56
+ # bands so it dominates them, yields the code the run had already
57
+ # computed: the contract's own guarantee, that the exit code reports the
58
+ # annotations, survives a truncated pipe. When the EPIPE fires before
59
+ # that computation — the reader closing while the validator is still
60
+ # running — there is no computed code to yield and none may be invented:
61
+ # {EXIT_OK} stands, because nothing reached the reader and neither
62
+ # "malformed annotations" nor "the linter is broken" was measured. This
63
+ # is a decision about what the shell is told, recorded here for the same
64
+ # reason the one above is.
65
+ #
43
66
  # == All failures, not the first
44
67
  #
45
68
  # SPGD-12 §1 step 4 says the linter "exits 1 on the *first* malformed
@@ -163,6 +186,17 @@ module SpecGuard
163
186
  json: options[:json], ok: code == EXIT_OK)
164
187
 
165
188
  code
189
+ rescue Errno::EPIPE
190
+ # The pipe's reader stopped listening — `| head`, a quitting pager, a
191
+ # CI log tailer. The run is correct and its verdict stands; yield it
192
+ # rather than the backstop's "the tool is broken". `code` is nil when
193
+ # the EPIPE fired before the verdict was computed (the reader closed
194
+ # while the validator was still running), and then {EXIT_OK} stands:
195
+ # a bare `code` would be nil, `exit(nil)` in bin/specguard-lint
196
+ # raises TypeError and hands the shell 1 — the code this contract
197
+ # has already spent on "malformed annotations". See the class
198
+ # comment.
199
+ code || EXIT_OK
166
200
  rescue UsageError, ValidatorError => e
167
201
  @stderr.puts "specguard-lint: error: #{e.message}"
168
202
  EXIT_MISUSE
@@ -49,6 +49,20 @@ module SpecGuard
49
49
  # `Interrupt`, `SignalException` and `SystemExit` are deliberately not
50
50
  # caught. Ctrl-C halfway through a 40-line file must stay Ctrl-C.
51
51
  #
52
+ # `Errno::EPIPE` joins them, and for the shell's side of the same reason
53
+ # (SPGD-1288). A truncated report — `--list` into `head`, a CI log
54
+ # tailer that stopped reading — is not this tool failing:
55
+ # the deliveries all happened and the per-line verdicts are in hand, and
56
+ # the reader simply stopped listening. Left to the backstop it is a
57
+ # fabricated 2 with an `internal error:` line — on `--list`, a 0 → 2
58
+ # flip on a clean listing. So the rescue below catches it ahead of the
59
+ # bands and yields the code the run had already computed: {#exit_code}
60
+ # over the results when they exist, {EXIT_OK} when the pipe closed
61
+ # before any verdict did — the `--list` path builds none, and a run that
62
+ # reported nothing has no verdict for an exit code to carry. On the
63
+ # delivery path a truncated report that exits 2 is exiting with its
64
+ # legitimate `:undelivered` code, not the backstop's.
65
+ #
52
66
  # == Where the line between 1 and 2 actually falls
53
67
  #
54
68
  # Not where {Transport::Result} draws it. That struct answers `:rejected`
@@ -402,6 +416,15 @@ module SpecGuard
402
416
 
403
417
  report(source, results, json: options.json)
404
418
  exit_code(results)
419
+ rescue Errno::EPIPE
420
+ # The report's reader stopped listening — `| head`, a quitting pager,
421
+ # a CI log tailer. The deliveries happened and the per-line verdicts
422
+ # are in hand, so the code is the run's own, recomputed from
423
+ # `results`, not the backstop's "the tool is broken". `results` is
424
+ # nil on the `--list` path, which builds none, and when the pipe
425
+ # closed before any delivery was made; then {EXIT_OK} stands. See
426
+ # the class comment.
427
+ results ? exit_code(results) : EXIT_OK
405
428
  rescue UsageError => e
406
429
  @stderr.puts "specguard-ingest: error: #{e.message}"
407
430
  EXIT_MISUSE
@@ -1154,6 +1154,20 @@ module SpecGuard
1154
1154
 
1155
1155
  check_status(status, stderr)
1156
1156
  parse_document(stdout, stderr)
1157
+ rescue Errno::EPIPE
1158
+ # An EPIPE here is about THIS process's own stdout, not the child:
1159
+ # `Open3.capture3` flushes the parent's buffered output while
1160
+ # setting up the child, and when the reader of that pipe — `| head`,
1161
+ # a quitting pager, a CI log tailer — has gone, it is that flush
1162
+ # which raises. The rescue below was written for a child that
1163
+ # cannot execute; re-wrapping this one would report "the validator
1164
+ # could not be executed", accusing the configured backend of a
1165
+ # fault that does not exist, and {CLI}'s EPIPE band — which sits
1166
+ # ahead of its `ValidatorError` band precisely for this — would
1167
+ # never see the exception at all. So it propagates as itself.
1168
+ # Every OTHER `SystemCallError` keeps the rescue below: ENOENT,
1169
+ # EACCES, ENOEXEC and E2BIG remain validator failures and exit 2.
1170
+ raise
1157
1171
  rescue SystemCallError => e
1158
1172
  # ENOENT/EACCES between #verify! and here (a binary deleted or
1159
1173
  # chmod'ed mid-run), ENOEXEC for a file that is not a program, E2BIG
@@ -7,5 +7,5 @@
7
7
  # framework-scoped version constant a lie, so the number moved here and the
8
8
  # rspec module now points at it for back-compat.
9
9
  module SpecGuard
10
- VERSION = "0.3.18"
10
+ VERSION = "0.3.19"
11
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: specguard-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.18
4
+ version: 0.3.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - specguard Agent
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-19 00:00:00.000000000 Z
11
+ date: 2026-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json