bug_bunny 5.0.0 → 5.1.0
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 +4 -4
- data/AGENTS.md +1 -1
- data/CHANGELOG.md +8 -0
- data/docs/test/{test.md → testing.md} +5 -5
- data/lib/bug_bunny/resource.rb +15 -1
- data/lib/bug_bunny/version.rb +1 -1
- data/skill/references/resource.md +18 -0
- data/spec/unit/extra_top_level_params_spec.rb +70 -0
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 877e5f5961f53d587b2bc67e6a8c39d247b996e1272ddad076236633df65f267
|
|
4
|
+
data.tar.gz: 6928594ae30624f1dccd2841594bee4b0faed40ee0cd238a69387399559a757b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fea6d7206396aae6ff2b35277e651ed944bee590f74200a392f2fb962af8757f56057b6d637434a91603d272b59b6215b459b330e98999d37f72d1c2ad6af763
|
|
7
|
+
data.tar.gz: b9d531b234ec094ab7127ea5921506d92a32e57961463904e6a62e158ce8a8e3020368ff1c6006cb30ae62a5beea942f3c004ce33e91362c910de2e87165aa6e
|
data/AGENTS.md
CHANGED
|
@@ -17,7 +17,7 @@ proyecto y convenciones de equipo, ver `CLAUDE.md`. Para la entrada humana, ver
|
|
|
17
17
|
| Errores | `docs/errors/errors.md` | completo (§a/b/d estructura + §c política inferida) | jerarquía de excepciones públicas, mapeo `status→excepción`, shape del payload, política retry |
|
|
18
18
|
| Configuración | `docs/config/configuracion.md` | completo (estructura + enrich §f/g/h) | opciones de `Configuration`, defaults, failure-mode/threading, inyecciones del `Railtie`, ENV sugeridas |
|
|
19
19
|
| Dependencias consumidas | `docs/consumed/rabbitmq.md` | completo (estructura + enrich §c/e) | qué consume del broker RabbitMQ vía `bunny`, mapeo error-Bunny→excepción, retry/degradación |
|
|
20
|
-
| Test | `docs/test/
|
|
20
|
+
| Test | `docs/test/testing.md` | completo (estructura + enrich §e-h) | suites RSpec/Minitest, CI, contract-assessment, link a incidentes (#49/#52) |
|
|
21
21
|
| Release | `docs/release/release.md` | completo | patrón gema-tag, versionado, publish a RubyGems |
|
|
22
22
|
| Datos | — | n/a | gema sin DB |
|
|
23
23
|
| Operaciones / Interfaz / Topología | — | dev-structure F2 no implementado | contrato embebido en `README.md`/`skill/SKILL.md` (interim RFC-008 §2) |
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [5.1.0] - 2026-07-22
|
|
4
|
+
|
|
5
|
+
### Nuevas funcionalidades
|
|
6
|
+
- **Hook `extra_top_level_params` en `Resource#save`:** una subclase puede sobrescribirlo (default `{}`) para mergear datos TOP-LEVEL hermanos del recurso en el body del `save` —fuera del wrapper `param_key`— sin que sean atributos del recurso ni se persistan en el modelo. Caso de uso: un dato de transporte (p. ej. una credencial) que el servidor lee como `params[:x]`. No-breaking (el default `{}` deja el body idéntico para los recursos que no lo sobrescriben). — @Pslp
|
|
7
|
+
|
|
8
|
+
### Documentación
|
|
9
|
+
- `docs/test/` incrementado (spec `extra_top_level_params`, conteos 16 unit / 23 total) y renombrado a `docs/test/testing.md` (filename canónico RFC-013). Hook documentado en el contrato interino `skill/references/resource.md`. — @Pslp
|
|
10
|
+
|
|
3
11
|
## [5.0.0] - 2026-07-01
|
|
4
12
|
|
|
5
13
|
> **BREAKING.** Se elimina la constante pública `BugBunny::SecurityError`. Aunque la excepción nunca se *levantaba*, su **ausencia rompe en evaluación**: un `rescue BugBunny::SecurityError` en un consumidor resuelve la constante cuando *cualquier* excepción entra a ese bloque → `NameError` que enmascara la excepción original. Por eso es breaking real, no inerte.
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Test — bug_bunny
|
|
2
2
|
|
|
3
3
|
> meta: artefacto test · RFC-013 · generado `arch-structure` (§a-§d) +
|
|
4
|
-
> `arch-enrich` (§e-§h) · anclado a `
|
|
4
|
+
> `arch-enrich` (§e-§h) · anclado a `7bf1da7`, `Rakefile`, `bug_bunny.gemspec`,
|
|
5
5
|
> `spec/spec_helper.rb`, `spec/support/integration_helper.rb`,
|
|
6
|
-
> `.github/workflows/main.yml`, `CHANGELOG.md` · fecha 2026-
|
|
6
|
+
> `.github/workflows/main.yml`, `CHANGELOG.md` · fecha 2026-07-22 · cobertura:
|
|
7
7
|
> §a-§d (estructura) + §e-§h (enrich, anclado a specs/CHANGELOG) completas.
|
|
8
8
|
|
|
9
9
|
## 1. Resumen
|
|
10
10
|
|
|
11
|
-
Suite principal **RSpec** (`spec/`,
|
|
11
|
+
Suite principal **RSpec** (`spec/`, 23 specs: 16 unit + 7 integration). Tarea
|
|
12
12
|
`:test` legacy de **Minitest** (`test/`, 2 archivos) fuera del default y del CI.
|
|
13
13
|
CI corre `bundle exec rake` (= `:spec`) en Ruby 3.4.4. Sin coverage tool
|
|
14
14
|
configurado.
|
|
@@ -19,7 +19,7 @@ configurado.
|
|
|
19
19
|
|
|
20
20
|
| framework | dir | nivel | nº | propósito |
|
|
21
21
|
|---|---|---|---|---|
|
|
22
|
-
| **RSpec** `~> 3.0` | `spec/unit/` | unit |
|
|
22
|
+
| **RSpec** `~> 3.0` | `spec/unit/` | unit | 16 | client/session pool, configuration, consumer, producer, controller, raise_error, remote_error, request, route, observability, otel, resource, middleware, `extra_top_level_params` (hook de params hermanos en `Resource#save`) |
|
|
23
23
|
| **RSpec** | `spec/integration/` | integration | 7 | client, consumer_middleware, controller, error_handling, infrastructure, publisher_confirms, resource — **requieren RabbitMQ real** (usan `BugBunny.create_connection` + pool) |
|
|
24
24
|
| **Minitest** `~> 5.0` (+ `mocha`, `minitest-reporters`) | `test/integration/` | integration (legacy) | 2 | `manual_client_test.rb`, `infrastructure_test.rb` — tarea `:test`, **no** en default ni CI |
|
|
25
25
|
|
|
@@ -60,7 +60,7 @@ umbral de coverage declarado.
|
|
|
60
60
|
- **Integration specs no corren en CI:** `main.yml` no declara servicio RabbitMQ;
|
|
61
61
|
las 7 integration specs **se skipean** vía `rabbitmq_available?`
|
|
62
62
|
(`spec/support/integration_helper.rb:14`, ver `publisher_confirms_spec.rb:10`).
|
|
63
|
-
En CI solo se ejercitan las **
|
|
63
|
+
En CI solo se ejercitan las **16 unit specs** → el contrato AMQP real (publish/
|
|
64
64
|
consume/confirms contra broker) **no se valida en pipeline**, solo localmente
|
|
65
65
|
con broker. Gap relevante.
|
|
66
66
|
- **Sin medición de cobertura:** no hay SimpleCov ni umbral → la cobertura no está
|
data/lib/bug_bunny/resource.rb
CHANGED
|
@@ -440,7 +440,7 @@ module BugBunny
|
|
|
440
440
|
rk = calculate_routing_key(id)
|
|
441
441
|
flat_payload = changes_to_send
|
|
442
442
|
key = self.class.param_key
|
|
443
|
-
wrapped_payload = { key => flat_payload }
|
|
443
|
+
wrapped_payload = { key => flat_payload }.merge(extra_top_level_params)
|
|
444
444
|
|
|
445
445
|
path = is_new ? self.class.resource_name : "#{self.class.resource_name}/#{id}"
|
|
446
446
|
method = is_new ? :post : :put
|
|
@@ -467,6 +467,20 @@ module BugBunny
|
|
|
467
467
|
false
|
|
468
468
|
end
|
|
469
469
|
|
|
470
|
+
# Params top-level extra a incluir en el body del `save`, JUNTO al recurso
|
|
471
|
+
# envuelto en `param_key` (no dentro de él). Default: ninguno.
|
|
472
|
+
#
|
|
473
|
+
# Las subclases lo sobrescriben para enviar datos HERMANOS del recurso que no
|
|
474
|
+
# forman parte de sus atributos ni deben persistir en el modelo — p. ej. una
|
|
475
|
+
# credencial de transporte que el servidor lee como `params[:x]` y que no se
|
|
476
|
+
# serializa dentro del recurso. Se mergea sobre `{ param_key => attrs }`, así
|
|
477
|
+
# que no debe usar `param_key` como clave (colisionaría con el recurso).
|
|
478
|
+
#
|
|
479
|
+
# @return [Hash]
|
|
480
|
+
def extra_top_level_params
|
|
481
|
+
{}
|
|
482
|
+
end
|
|
483
|
+
|
|
470
484
|
# Elimina el recurso del servidor remoto (DELETE).
|
|
471
485
|
#
|
|
472
486
|
# @return [Boolean]
|
data/lib/bug_bunny/version.rb
CHANGED
|
@@ -65,6 +65,24 @@ order.errors # ActiveModel::Errors
|
|
|
65
65
|
- **Existente** (`persisted? == true`): Envía PUT solo con atributos cambiados (`changes_to_send`).
|
|
66
66
|
- Captura `BugBunny::UnprocessableEntity` (422) y carga `resource.errors`. Retorna `false`.
|
|
67
67
|
|
|
68
|
+
### Params top-level hermanos: `extra_top_level_params`
|
|
69
|
+
|
|
70
|
+
Por default `save` envía el body `{ param_key => attrs }`. Una subclase puede sobrescribir `extra_top_level_params` (default `{}`) para mergear datos **top-level hermanos** del recurso —fuera del wrapper `param_key`— sin que sean atributos del recurso ni se persistan en el modelo. Caso de uso: un dato de transporte (p. ej. una credencial) que el servidor lee como `params[:x]`.
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
class Service < BugBunny::Resource
|
|
74
|
+
self.param_key = 'service'
|
|
75
|
+
attr_accessor :registry_auth # dato transiente, NO atributo del recurso
|
|
76
|
+
|
|
77
|
+
def extra_top_level_params
|
|
78
|
+
registry_auth ? { registry_auth: registry_auth } : {}
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
# save envía: { 'service' => { ...attrs }, registry_auth: '...' }
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
No debe usar `param_key` como clave (colisionaría con el wrapper del recurso).
|
|
85
|
+
|
|
68
86
|
## Contexto Dinámico (.with)
|
|
69
87
|
|
|
70
88
|
### Forma de bloque (recomendada)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
# Hook `extra_top_level_params`: permite a una subclase mandar params HERMANOS del
|
|
6
|
+
# recurso en el body del `save` (top-level, junto al `param_key`), sin que formen
|
|
7
|
+
# parte de los atributos del recurso ni se persistan en el modelo. Caso de uso:
|
|
8
|
+
# una credencial de transporte que el servidor lee como `params[:x]`.
|
|
9
|
+
module ExtraTopLevelParamsSpec
|
|
10
|
+
# Recurso sin override: usa el hook por default (no manda extras).
|
|
11
|
+
class Plain < BugBunny::Resource
|
|
12
|
+
self.resource_name = 'widget'
|
|
13
|
+
self.param_key = 'widget'
|
|
14
|
+
self.exchange = 'etlp_ex'
|
|
15
|
+
self.exchange_type = 'direct'
|
|
16
|
+
attribute :name, :string
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Recurso que sobrescribe el hook para mandar un sibling transiente (no atributo).
|
|
20
|
+
class WithSibling < BugBunny::Resource
|
|
21
|
+
self.resource_name = 'service'
|
|
22
|
+
self.param_key = 'service'
|
|
23
|
+
self.exchange = 'etlp_ex'
|
|
24
|
+
self.exchange_type = 'direct'
|
|
25
|
+
attribute :name, :string
|
|
26
|
+
|
|
27
|
+
attr_accessor :registry_auth
|
|
28
|
+
|
|
29
|
+
def extra_top_level_params
|
|
30
|
+
registry_auth ? { registry_auth: registry_auth } : {}
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
RSpec.describe 'BugBunny::Resource#extra_top_level_params' do
|
|
36
|
+
let(:client) { instance_double(BugBunny::Client) }
|
|
37
|
+
|
|
38
|
+
before do
|
|
39
|
+
allow(client).to receive(:request) do |_path, **args|
|
|
40
|
+
@sent_body = args[:body]
|
|
41
|
+
{ 'body' => {} }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def save_with_stub(resource)
|
|
46
|
+
allow(resource).to receive(:bug_bunny_client).and_return(client)
|
|
47
|
+
resource.save
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'default: el body solo envuelve el recurso en param_key (sin extras)' do
|
|
51
|
+
save_with_stub(ExtraTopLevelParamsSpec::Plain.new(name: 'w'))
|
|
52
|
+
|
|
53
|
+
expect(@sent_body.keys).to eq(['widget'])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'override: agrega el sibling top-level JUNTO al recurso envuelto, no adentro' do
|
|
57
|
+
resource = ExtraTopLevelParamsSpec::WithSibling.new(name: 's').tap { |r| r.registry_auth = 'b64cred' }
|
|
58
|
+
|
|
59
|
+
save_with_stub(resource)
|
|
60
|
+
|
|
61
|
+
expect(@sent_body[:registry_auth]).to eq('b64cred')
|
|
62
|
+
expect(@sent_body['service']).not_to have_key('registry_auth')
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'override sin valor: no agrega el sibling (hook devuelve {})' do
|
|
66
|
+
save_with_stub(ExtraTopLevelParamsSpec::WithSibling.new(name: 's'))
|
|
67
|
+
|
|
68
|
+
expect(@sent_body.keys).to eq(['service'])
|
|
69
|
+
end
|
|
70
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bug_bunny
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- gabix
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bunny
|
|
@@ -240,7 +240,7 @@ files:
|
|
|
240
240
|
- docs/errors/errors.md
|
|
241
241
|
- docs/glossary/glossary.md
|
|
242
242
|
- docs/release/release.md
|
|
243
|
-
- docs/test/
|
|
243
|
+
- docs/test/testing.md
|
|
244
244
|
- initializer_example.rb
|
|
245
245
|
- lib/bug_bunny.rb
|
|
246
246
|
- lib/bug_bunny/client.rb
|
|
@@ -294,6 +294,7 @@ files:
|
|
|
294
294
|
- spec/unit/consumer_middleware_spec.rb
|
|
295
295
|
- spec/unit/consumer_spec.rb
|
|
296
296
|
- spec/unit/controller_after_action_spec.rb
|
|
297
|
+
- spec/unit/extra_top_level_params_spec.rb
|
|
297
298
|
- spec/unit/observability_spec.rb
|
|
298
299
|
- spec/unit/otel_spec.rb
|
|
299
300
|
- spec/unit/producer_spec.rb
|
|
@@ -313,7 +314,7 @@ metadata:
|
|
|
313
314
|
homepage_uri: https://github.com/gedera/bug_bunny
|
|
314
315
|
source_code_uri: https://github.com/gedera/bug_bunny
|
|
315
316
|
changelog_uri: https://github.com/gedera/bug_bunny/blob/main/CHANGELOG.md
|
|
316
|
-
documentation_uri: https://github.com/gedera/bug_bunny/blob/v5.
|
|
317
|
+
documentation_uri: https://github.com/gedera/bug_bunny/blob/v5.1.0/skill
|
|
317
318
|
post_install_message:
|
|
318
319
|
rdoc_options: []
|
|
319
320
|
require_paths:
|