bug_bunny 4.13.0 → 4.14.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/CHANGELOG.md +14 -0
- data/README.md +16 -0
- data/lib/bug_bunny/producer.rb +50 -7
- data/lib/bug_bunny/version.rb +1 -1
- data/skill/SKILL.md +31 -0
- data/skill/references/client-middleware.md +3 -0
- data/spec/unit/producer_spec.rb +59 -0
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6081a471e20278bc190a7d7517b69cf6fe6d852293bca353974c5ba1cbe4e746
|
|
4
|
+
data.tar.gz: 2e1b952c9627b7f3f1f9ab1e2af25af49ca0422ff59f062ac7499c14265d6a57
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6cf7de01b98c925c8f02de1e09aafc0113f24f93145498ace1616445deecf6319bde3464d9afcd89b5b461904fbe878d4bfb24ea3a2a310149a32f6f2b06f4d0
|
|
7
|
+
data.tar.gz: 2560004c6036b238456fe9c9af9bf478dde67b1ff07240fdac942ecab303467d1db04f3029c2579463e5017b7c9f25ad2e5f1c5ef2c999f86bcde0bedb42eb67
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [4.14.0] - 2026-05-12
|
|
4
|
+
|
|
5
|
+
### Nuevas funcionalidades
|
|
6
|
+
- **Duraciones medidas internamente en el Producer:** BugBunny ahora emite `duration_s` automáticamente en los eventos del publisher siguiendo las [OpenTelemetry metric semantic conventions](https://opentelemetry.io/docs/specs/semconv/general/metrics/) (`Float` en segundos). El código de aplicación ya no necesita envolver `client.publish` con `Process.clock_gettime`. — @Gabriel
|
|
7
|
+
- `producer.published` (INFO): `duration_s` del `basic_publish` (TCP enqueue al broker, sin esperar ACK).
|
|
8
|
+
- `producer.confirmed` (INFO): tres duraciones desglosadas — `publish_duration_s`, `confirm_duration_s` (espera de `wait_for_confirms`) y `duration_s` total. Útil para distinguir latencia de red vs latencia del confirm policy del broker.
|
|
9
|
+
- `producer.rpc_response_received`: ahora incluye `duration_s` con el round-trip RPC completo (publish + procesamiento remoto + reply).
|
|
10
|
+
|
|
11
|
+
### Cambios de comportamiento
|
|
12
|
+
- **`producer.rpc_response_received` promovido de DEBUG a INFO.** No es breaking de API pero aumenta el volumen de logs en clientes RPC. Si el cambio impacta tu pipeline de observabilidad, filtralo por nivel.
|
|
13
|
+
|
|
14
|
+
### Documentación
|
|
15
|
+
- README + `skill/SKILL.md` + `skill/references/client-middleware.md` actualizados con el catálogo completo de eventos de log emitidos por la gema y la tabla de qué mide cada `duration_s`. Mensaje explícito en ambas audiencias (humana + agente) advirtiendo no duplicar la medición en código de aplicación.
|
|
16
|
+
|
|
3
17
|
## [4.13.0] - 2026-05-11
|
|
4
18
|
|
|
5
19
|
### Nuevas funcionalidades
|
data/README.md
CHANGED
|
@@ -252,11 +252,27 @@ BugBunny implementa de forma nativa las [OpenTelemetry semantic conventions for
|
|
|
252
252
|
Todos los eventos internos se emiten como logs `key=value` compatibles con Datadog, CloudWatch, ELK y ExisRay.
|
|
253
253
|
|
|
254
254
|
```
|
|
255
|
+
component=bug_bunny event=producer.publish method=POST path=acct/publish messaging_destination_name=acct_x messaging_routing_key=acct.start.42
|
|
256
|
+
component=bug_bunny event=producer.published method=POST path=acct/publish routing_key=acct.start.42 messaging_message_id=corr-1 duration_s=0.000812
|
|
257
|
+
component=bug_bunny event=producer.confirmed method=POST path=acct/publish routing_key=acct.start.42 publish_duration_s=0.000812 confirm_duration_s=0.012 duration_s=0.013
|
|
258
|
+
component=bug_bunny event=producer.rpc_response_received method=GET path=users/42 duration_s=0.034 messaging_operation=receive
|
|
255
259
|
component=bug_bunny event=consumer.message_processed status=200 duration_s=0.012 messaging_operation=process controller=NodesController action=show
|
|
256
260
|
component=bug_bunny event=consumer.execution_error error_class=RuntimeError error_message="..." duration_s=0.003
|
|
257
261
|
component=bug_bunny event=consumer.connection_error attempt_count=2 retry_in_s=10 error_message="..."
|
|
258
262
|
```
|
|
259
263
|
|
|
264
|
+
### Duraciones medidas internamente
|
|
265
|
+
|
|
266
|
+
BugBunny mide y emite duraciones automáticamente — **no es necesario envolver llamadas a `client.publish` con `Process.clock_gettime` en el código de aplicación**. Las unidades siguen las [OpenTelemetry metric semantic conventions](https://opentelemetry.io/docs/specs/semconv/general/metrics/) (`s`, segundos como `Float`).
|
|
267
|
+
|
|
268
|
+
| Evento | Duración | Mide |
|
|
269
|
+
|---|---|---|
|
|
270
|
+
| `producer.published` | `duration_s` | Solo el `basic_publish` (TCP enqueue al broker). |
|
|
271
|
+
| `producer.confirmed` | `publish_duration_s` + `confirm_duration_s` + `duration_s` (total) | Publish + espera de ACK del broker. |
|
|
272
|
+
| `producer.rpc_response_received` | `duration_s` | Round-trip RPC completo (publish + procesamiento remoto + reply). |
|
|
273
|
+
| `consumer.message_processed` | `duration_s` | Procesamiento del mensaje (router + controller + reply). |
|
|
274
|
+
| `consumer.execution_error` | `duration_s` | Tiempo transcurrido hasta el error. |
|
|
275
|
+
|
|
260
276
|
Las claves sensibles (`password`, `token`, `secret`, `api_key`, `authorization`, etc.) se filtran automáticamente a `[FILTERED]` en toda la salida de logs.
|
|
261
277
|
|
|
262
278
|
---
|
data/lib/bug_bunny/producer.rb
CHANGED
|
@@ -60,9 +60,16 @@ module BugBunny
|
|
|
60
60
|
# (default `true` — ver {BugBunny::Configuration#nack_raise}).
|
|
61
61
|
# @raise [BugBunny::CommunicationError] Si el canal AMQP falla durante la publicación o confirm.
|
|
62
62
|
def confirmed(request)
|
|
63
|
-
|
|
63
|
+
started_at = monotonic_now
|
|
64
|
+
publish_duration = publish_message(request)
|
|
65
|
+
|
|
66
|
+
confirm_started_at = monotonic_now
|
|
64
67
|
acked = wait_for_confirms!(request)
|
|
68
|
+
confirm_duration = duration_s(confirm_started_at)
|
|
69
|
+
|
|
65
70
|
handle_confirm_result(request, acked)
|
|
71
|
+
log_confirmed(request, publish_duration, confirm_duration, started_at)
|
|
72
|
+
|
|
66
73
|
{ 'status' => 202, 'body' => nil }
|
|
67
74
|
rescue BugBunny::Error
|
|
68
75
|
raise
|
|
@@ -90,6 +97,7 @@ module BugBunny
|
|
|
90
97
|
future = Concurrent::IVar.new
|
|
91
98
|
@pending_requests[cid] = future
|
|
92
99
|
|
|
100
|
+
started_at = monotonic_now
|
|
93
101
|
begin
|
|
94
102
|
fire(request)
|
|
95
103
|
|
|
@@ -101,11 +109,7 @@ module BugBunny
|
|
|
101
109
|
raise BugBunny::RequestTimeout, "Timeout waiting for RPC: #{request.path} [#{request.method}]" if result.nil?
|
|
102
110
|
|
|
103
111
|
BugBunny.configuration.on_rpc_reply&.call(result[:headers])
|
|
104
|
-
|
|
105
|
-
safe_log(:debug, 'producer.rpc_response_received',
|
|
106
|
-
messaging_system: 'rabbitmq', messaging_operation: 'receive', messaging_message_id: cid,
|
|
107
|
-
response_body: result[:body]&.truncate(500),
|
|
108
|
-
response_headers: result[:headers]&.to_json&.truncate(300))
|
|
112
|
+
log_rpc_response_received(request, cid, result, started_at)
|
|
109
113
|
|
|
110
114
|
parse_response(result[:body])
|
|
111
115
|
ensure
|
|
@@ -119,8 +123,11 @@ module BugBunny
|
|
|
119
123
|
# Resuelve exchange, serializa payload, logea y publica el mensaje.
|
|
120
124
|
# Compartido por {#fire} y {#confirmed}.
|
|
121
125
|
#
|
|
126
|
+
# Emite `producer.publish` antes y `producer.published` después con `duration_s`
|
|
127
|
+
# midiendo solo el `basic_publish` (TCP enqueue al broker, sin esperar ACK).
|
|
128
|
+
#
|
|
122
129
|
# @param request [BugBunny::Request]
|
|
123
|
-
# @return [
|
|
130
|
+
# @return [Float] duración del publish en segundos.
|
|
124
131
|
def publish_message(request)
|
|
125
132
|
x = @session.exchange(
|
|
126
133
|
name: request.exchange,
|
|
@@ -129,7 +136,43 @@ module BugBunny
|
|
|
129
136
|
)
|
|
130
137
|
payload = serialize_message(request.body)
|
|
131
138
|
log_request(request, payload)
|
|
139
|
+
|
|
140
|
+
started_at = monotonic_now
|
|
132
141
|
x.publish(payload, request.amqp_options.merge(routing_key: request.final_routing_key))
|
|
142
|
+
publish_duration = duration_s(started_at)
|
|
143
|
+
|
|
144
|
+
log_published(request, publish_duration)
|
|
145
|
+
publish_duration
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# @api private
|
|
149
|
+
def log_published(request, publish_duration_s)
|
|
150
|
+
safe_log(:info, 'producer.published',
|
|
151
|
+
method: request.method.to_s.upcase, path: request.path,
|
|
152
|
+
routing_key: request.final_routing_key,
|
|
153
|
+
messaging_message_id: request.correlation_id,
|
|
154
|
+
duration_s: publish_duration_s)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# @api private
|
|
158
|
+
def log_rpc_response_received(request, cid, result, started_at)
|
|
159
|
+
safe_log(:info, 'producer.rpc_response_received',
|
|
160
|
+
method: request.method.to_s.upcase, path: request.path,
|
|
161
|
+
messaging_system: 'rabbitmq', messaging_operation: 'receive', messaging_message_id: cid,
|
|
162
|
+
duration_s: duration_s(started_at),
|
|
163
|
+
response_body: result[:body]&.truncate(500),
|
|
164
|
+
response_headers: result[:headers]&.to_json&.truncate(300))
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# @api private
|
|
168
|
+
def log_confirmed(request, publish_duration_s, confirm_duration_s, started_at)
|
|
169
|
+
safe_log(:info, 'producer.confirmed',
|
|
170
|
+
method: request.method.to_s.upcase, path: request.path,
|
|
171
|
+
routing_key: request.final_routing_key,
|
|
172
|
+
messaging_message_id: request.correlation_id,
|
|
173
|
+
publish_duration_s: publish_duration_s,
|
|
174
|
+
confirm_duration_s: confirm_duration_s,
|
|
175
|
+
duration_s: duration_s(started_at))
|
|
133
176
|
end
|
|
134
177
|
|
|
135
178
|
# Espera la confirmación del broker con timeout opcional.
|
data/lib/bug_bunny/version.rb
CHANGED
data/skill/SKILL.md
CHANGED
|
@@ -97,6 +97,37 @@ BugBunny implementa las [OpenTelemetry semantic conventions for messaging](https
|
|
|
97
97
|
- **Consumer:** Extrae los campos de los logs estructurados sin mutar los headers originales. Los eventos `consumer.message_received` y `consumer.message_processed` incluyen estos campos automáticamente.
|
|
98
98
|
- **RPC Reply:** El consumer inyecta los mismos campos en el reply para cerrar el ciclo de traza del lado del cliente.
|
|
99
99
|
|
|
100
|
+
### Eventos de log y duraciones internas
|
|
101
|
+
|
|
102
|
+
BugBunny mide y emite duraciones automáticamente. **No envolver llamadas a `client.publish` con `Process.clock_gettime` en código de aplicación** — duplica el trabajo. Las duraciones siguen las [OpenTelemetry metric semantic conventions](https://opentelemetry.io/docs/specs/semconv/general/metrics/) (`duration_s` como `Float` en segundos).
|
|
103
|
+
|
|
104
|
+
| Evento | Nivel | Emitido por | Campos clave |
|
|
105
|
+
|---|---|---|---|
|
|
106
|
+
| `producer.publish` | INFO | `Producer#publish_message` (pre) | `method`, `path`, `messaging_*` |
|
|
107
|
+
| `producer.publish_payload` | INFO | `Producer#publish_message` | `payload` (truncado), `body_size` |
|
|
108
|
+
| `producer.publish_detail` | DEBUG | `Producer#publish_message` | `exchange_opts` final |
|
|
109
|
+
| `producer.published` | INFO | `Producer#publish_message` (post) | `method`, `path`, `routing_key`, `messaging_message_id`, **`duration_s`** (publish solo) |
|
|
110
|
+
| `producer.confirmed` | INFO | `Producer#confirmed` (post-ACK) | `method`, `path`, `routing_key`, **`publish_duration_s`**, **`confirm_duration_s`**, **`duration_s`** (total) |
|
|
111
|
+
| `producer.confirms_nacked` | WARN | `Producer#confirmed` (NACK) | `count`, `path` |
|
|
112
|
+
| `producer.rpc_waiting` | DEBUG | `Producer#rpc` | `messaging_message_id`, `timeout_s` |
|
|
113
|
+
| `producer.rpc_response_received` | INFO | `Producer#rpc` (reply recibido) | `method`, `path`, **`duration_s`** (round-trip total), `response_body` |
|
|
114
|
+
| `producer.rpc_response_orphaned` | WARN | reply listener | `correlation_id` |
|
|
115
|
+
| `consumer.message_received` | INFO | `Consumer#process_message` | `method`, `path`, `messaging_*` |
|
|
116
|
+
| `consumer.message_processed` | INFO | `Consumer#process_message` (post) | `response_status`, **`duration_s`**, `controller`, `action`, `messaging_*` |
|
|
117
|
+
| `consumer.execution_error` | ERROR | `Consumer#process_message` (rescue) | **`duration_s`**, `error_class`, `error_message` |
|
|
118
|
+
| `consumer.route_not_found` | WARN | `Consumer#process_message` | `method`, `path` |
|
|
119
|
+
| `consumer.connection_error` | ERROR | `Consumer#subscribe` (retry loop) | `attempt_count`, `retry_in_s`, `error_*` |
|
|
120
|
+
| `session.broker_return` | WARN | `Session` (mandatory unrouted) | `reply_code`, `reply_text`, `exchange`, `routing_key` |
|
|
121
|
+
|
|
122
|
+
**Resumen de qué mide cada `duration_s`:**
|
|
123
|
+
|
|
124
|
+
- `producer.published.duration_s` — solo el `basic_publish` (TCP enqueue al broker).
|
|
125
|
+
- `producer.confirmed.publish_duration_s` — el publish.
|
|
126
|
+
- `producer.confirmed.confirm_duration_s` — la espera del ACK del broker (`wait_for_confirms`).
|
|
127
|
+
- `producer.confirmed.duration_s` — total (publish + ACK).
|
|
128
|
+
- `producer.rpc_response_received.duration_s` — round-trip RPC completo (publish + procesamiento remoto + reply).
|
|
129
|
+
- `consumer.message_processed.duration_s` — procesamiento server-side (router + controller + reply).
|
|
130
|
+
|
|
100
131
|
---
|
|
101
132
|
|
|
102
133
|
## API: Configuración Global
|
|
@@ -59,11 +59,13 @@ El `Producer` es usado internamente por el `Client`. Implementa tres patrones de
|
|
|
59
59
|
- Reply listener (`basic_consume`) auto-iniciado en el primer RPC.
|
|
60
60
|
- Double-checked locking mutex para seguridad del listener.
|
|
61
61
|
- Timeout lanza `BugBunny::RequestTimeout`.
|
|
62
|
+
- **Emite `producer.rpc_response_received` (INFO) con `duration_s` = round-trip total** (publish + procesamiento remoto + reply). No medir en código de aplicación.
|
|
62
63
|
|
|
63
64
|
### Fire-and-Forget (`Producer#fire`)
|
|
64
65
|
|
|
65
66
|
- Publica en el exchange y retorna `{ 'status' => 202 }` inmediatamente.
|
|
66
67
|
- Sin confirmación de procesamiento.
|
|
68
|
+
- **Emite `producer.published` (INFO) con `duration_s`** = solo el `basic_publish` (TCP enqueue al broker).
|
|
67
69
|
|
|
68
70
|
### Confirmed (`Producer#confirmed`)
|
|
69
71
|
|
|
@@ -72,6 +74,7 @@ El `Producer` es usado internamente por el `Client`. Implementa tres patrones de
|
|
|
72
74
|
- Si `wait_for_confirms` devuelve `false` (broker NACKea), se logea `producer.confirms_nacked` con `count` y `path`. Por default (`config.nack_raise = true`) levanta `BugBunny::PublishNacked` con `path` y `nacked_count`. Para opt-out: `config.nack_raise = false` o pasar `nack_raise: false` per request — en ese caso solo logea y retorna 202.
|
|
73
75
|
- Si `mandatory: true` y el mensaje no es ruteable, el broker dispara `basic.return`. El handler se atacha vía `Bunny::Exchange#on_return` en `Session#exchange` la primera vez que se resuelve cada exchange (cacheado por nombre, una sola vez por canal) y delega a `Configuration#on_return` o al logger por default.
|
|
74
76
|
- Errores del canal se envuelven en `BugBunny::CommunicationError`; errores `BugBunny::Error` pre-existentes se propagan sin envolver.
|
|
77
|
+
- **Emite `producer.confirmed` (INFO) con tres duraciones desglosadas**: `publish_duration_s` (TCP enqueue), `confirm_duration_s` (`wait_for_confirms`), `duration_s` (total). Útil para distinguir latencia de red vs latencia de confirm policy del broker.
|
|
75
78
|
|
|
76
79
|
## Middleware Stack (Client-side, Onion Architecture)
|
|
77
80
|
|
data/spec/unit/producer_spec.rb
CHANGED
|
@@ -95,6 +95,31 @@ RSpec.describe BugBunny::Producer do
|
|
|
95
95
|
messaging_destination_name: 'events_x'
|
|
96
96
|
)
|
|
97
97
|
end
|
|
98
|
+
|
|
99
|
+
it 'producer.published incluye duration_s y campos de routing' do
|
|
100
|
+
request = BugBunny::Request.new('users')
|
|
101
|
+
request.exchange = 'users_x'
|
|
102
|
+
request.method = :post
|
|
103
|
+
request.correlation_id = 'corr-1'
|
|
104
|
+
|
|
105
|
+
fake_exchange = double('exchange')
|
|
106
|
+
allow(session).to receive(:exchange).and_return(fake_exchange)
|
|
107
|
+
allow(fake_exchange).to receive(:publish)
|
|
108
|
+
|
|
109
|
+
producer.fire(request)
|
|
110
|
+
|
|
111
|
+
published_event = logged_events.find { |e| e[:event] == 'producer.published' }
|
|
112
|
+
expect(published_event).not_to be_nil
|
|
113
|
+
expect(published_event[:level]).to eq(:info)
|
|
114
|
+
expect(published_event[:kwargs]).to include(
|
|
115
|
+
method: 'POST',
|
|
116
|
+
path: 'users',
|
|
117
|
+
routing_key: 'users',
|
|
118
|
+
messaging_message_id: 'corr-1'
|
|
119
|
+
)
|
|
120
|
+
expect(published_event[:kwargs][:duration_s]).to be_a(Numeric)
|
|
121
|
+
expect(published_event[:kwargs][:duration_s]).to be >= 0
|
|
122
|
+
end
|
|
98
123
|
end
|
|
99
124
|
|
|
100
125
|
describe '#rpc — log events incluyen campos OTel' do
|
|
@@ -182,6 +207,28 @@ RSpec.describe BugBunny::Producer do
|
|
|
182
207
|
messaging_message_id: 'corr-reply-test'
|
|
183
208
|
)
|
|
184
209
|
end
|
|
210
|
+
|
|
211
|
+
it 'producer.rpc_response_received incluye duration_s total' do
|
|
212
|
+
request = BugBunny::Request.new('users')
|
|
213
|
+
request.exchange = 'users_x'
|
|
214
|
+
request.method = :get
|
|
215
|
+
|
|
216
|
+
allow(rpc_producer).to receive(:ensure_reply_listener!)
|
|
217
|
+
|
|
218
|
+
ivar = Concurrent::IVar.new
|
|
219
|
+
allow(Concurrent::IVar).to receive(:new).and_return(ivar)
|
|
220
|
+
|
|
221
|
+
request.correlation_id = 'corr-dur'
|
|
222
|
+
rpc_producer.instance_variable_get(:@pending_requests)['corr-dur'] = ivar
|
|
223
|
+
|
|
224
|
+
Thread.new { ivar.set({ body: '{"ok":true}', headers: {} }) }.join(0.1)
|
|
225
|
+
|
|
226
|
+
rpc_producer.rpc(request)
|
|
227
|
+
|
|
228
|
+
response_event = logged_events.find { |e| e[:event] == 'producer.rpc_response_received' }
|
|
229
|
+
expect(response_event[:kwargs][:duration_s]).to be_a(Numeric)
|
|
230
|
+
expect(response_event[:kwargs][:duration_s]).to be >= 0
|
|
231
|
+
end
|
|
185
232
|
end
|
|
186
233
|
end
|
|
187
234
|
|
|
@@ -252,6 +299,18 @@ RSpec.describe BugBunny::Producer do
|
|
|
252
299
|
expect(nack_event).to be_nil
|
|
253
300
|
end
|
|
254
301
|
|
|
302
|
+
it 'logea producer.confirmed con publish_duration_s, confirm_duration_s y duration_s total' do
|
|
303
|
+
confirmed_producer.confirmed(build_request)
|
|
304
|
+
|
|
305
|
+
ev = logged_events.find { |e| e[:event] == 'producer.confirmed' }
|
|
306
|
+
expect(ev).not_to be_nil
|
|
307
|
+
expect(ev[:level]).to eq(:info)
|
|
308
|
+
expect(ev[:kwargs]).to include(method: 'POST', path: 'acct.start', routing_key: 'acct.start')
|
|
309
|
+
expect(ev[:kwargs][:publish_duration_s]).to be_a(Numeric)
|
|
310
|
+
expect(ev[:kwargs][:confirm_duration_s]).to be_a(Numeric)
|
|
311
|
+
expect(ev[:kwargs][:duration_s]).to be_a(Numeric)
|
|
312
|
+
end
|
|
313
|
+
|
|
255
314
|
context 'cuando el broker NACKea (wait_for_confirms devuelve false)' do
|
|
256
315
|
before do
|
|
257
316
|
allow(mock_channel).to receive(:wait_for_confirms).and_return(false)
|
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: 4.
|
|
4
|
+
version: 4.14.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-05-
|
|
11
|
+
date: 2026-05-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bunny
|
|
@@ -303,7 +303,7 @@ metadata:
|
|
|
303
303
|
homepage_uri: https://github.com/gedera/bug_bunny
|
|
304
304
|
source_code_uri: https://github.com/gedera/bug_bunny
|
|
305
305
|
changelog_uri: https://github.com/gedera/bug_bunny/blob/main/CHANGELOG.md
|
|
306
|
-
documentation_uri: https://github.com/gedera/bug_bunny/blob/v4.
|
|
306
|
+
documentation_uri: https://github.com/gedera/bug_bunny/blob/v4.14.0/skill
|
|
307
307
|
post_install_message:
|
|
308
308
|
rdoc_options: []
|
|
309
309
|
require_paths:
|