reqcord 0.1.2 → 0.1.4
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 +27 -1
- data/docs/configuration.md +32 -3
- data/examples/reqcord.yml +9 -2
- data/lib/reqcord/configuration.rb +19 -2
- data/lib/reqcord/generator.rb +24 -3
- data/lib/reqcord/route_collector.rb +4 -2
- data/lib/reqcord/version.rb +1 -1
- data/lib/tasks/reqcord.rake +33 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 87d47bb7440a886650db640312c804f7889a24420be0e1e2b81806ac4114a63c
|
|
4
|
+
data.tar.gz: d8198f3e86749a170c144bad28eae898f876c8e4a82ca933fa9d1a320204aaad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0f10290846b36da08d91f98998c8ef14c12427bf509bd8fb84d70a8b1f1bbec9dc389765e1b75be13d647f41000a1e295c39ffa89a70847c74ec84bb0e8ce3bf
|
|
7
|
+
data.tar.gz: e3c55c9f404b54b4ad2d284be04fc89f13ca5922c5ed52667c8ffad84fd808de3ef826e8b7ff97ad4e0dff8066a44af8122140cbfbb311257739c37b9430d088
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [0.1.
|
|
3
|
+
## [0.1.4] - 2026-09-16
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
* A failing test run no longer discards the output. The docs are generated
|
|
8
|
+
from what the suite captured, the warning names the exit status and the
|
|
9
|
+
report points out that routes reached only by failing tests are listed as
|
|
10
|
+
uncovered. The previous behaviour is `test.strict: true`.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
* `test.strict` (`REQCORD_STRICT=1`): abort on a failing suite instead of
|
|
15
|
+
documenting what it captured.
|
|
16
|
+
|
|
17
|
+
## [0.1.3] - 2026-09-16
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
* `routes.prefix` accepts a list (`[/v1, /v2, /partner]`) for APIs whose
|
|
22
|
+
versions or audiences do not share a root.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
* The `reqcord:init` template now names test directories (`test.paths`)
|
|
27
|
+
instead of running the whole suite, and documents every key inline.
|
|
28
|
+
|
|
29
|
+
## [0.1.2] - 2026-09-16
|
|
4
30
|
|
|
5
31
|
### Added
|
|
6
32
|
|
data/docs/configuration.md
CHANGED
|
@@ -52,6 +52,7 @@ before any test runs. YAML aliases are disabled.
|
|
|
52
52
|
| --- | --- |
|
|
53
53
|
| `REQCORD_TEST_FRAMEWORK` | `test.framework` |
|
|
54
54
|
| `REQCORD_TEST_COMMAND` | `test.command` (and therefore `test.paths`) |
|
|
55
|
+
| `REQCORD_STRICT` | `test.strict` (`1` or `true`) |
|
|
55
56
|
| `REQCORD_OUTPUT` | `output.directory` |
|
|
56
57
|
| `REQCORD_BASE_URL` | `variables.base_url` |
|
|
57
58
|
| `RESOURCE`, `VERSION` | run-time filters, see [Filtering a run](#filtering-a-run) |
|
|
@@ -123,9 +124,23 @@ absent.
|
|
|
123
124
|
|
|
124
125
|
With neither `paths` nor `command`, Reqcord runs `bin/rails test`.
|
|
125
126
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
### `test.strict`
|
|
128
|
+
|
|
129
|
+
Default `false`. What happens when the suite does not exit successfully:
|
|
130
|
+
|
|
131
|
+
* `false` — the run continues and documents what the tests captured. A
|
|
132
|
+
warning names the exit status, and the report reminds you that routes
|
|
133
|
+
exercised only by failing tests show up as *uncovered*. A test that failed
|
|
134
|
+
on an assertion after its request got a `2xx` still counts: the request
|
|
135
|
+
and response are what the application really did.
|
|
136
|
+
* `true` (or `REQCORD_STRICT=1`) — a failing suite aborts the run with
|
|
137
|
+
`Reqcord::GenerationError` and nothing is written. Use it in CI when the
|
|
138
|
+
generated docs are an artifact that must come from a green build.
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
test:
|
|
142
|
+
strict: true
|
|
143
|
+
```
|
|
129
144
|
|
|
130
145
|
---
|
|
131
146
|
|
|
@@ -146,6 +161,20 @@ routes:
|
|
|
146
161
|
prefix: /api/v2
|
|
147
162
|
```
|
|
148
163
|
|
|
164
|
+
A list documents routes under any of the prefixes — for APIs whose versions
|
|
165
|
+
or audiences do not share a root:
|
|
166
|
+
|
|
167
|
+
```yaml
|
|
168
|
+
routes:
|
|
169
|
+
prefix:
|
|
170
|
+
- /v1
|
|
171
|
+
- /v2
|
|
172
|
+
- /partner
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
One prefix already covers every version beneath it (`/api` includes `/api/v1`
|
|
176
|
+
and `/api/v2`); use `VERSION=v2` to generate for one of them.
|
|
177
|
+
|
|
149
178
|
Rails' own routes (`rails/…`, Active Storage, Action Mailbox, Turbo) are always
|
|
150
179
|
left out. `redirect(...)` routes and plain Rack mounts cannot be documented from
|
|
151
180
|
a test; they are counted as *skipped* in the report rather than dropped.
|
data/examples/reqcord.yml
CHANGED
|
@@ -19,9 +19,16 @@ test:
|
|
|
19
19
|
# Or spell the command out yourself; it wins over `paths`. Globs expand.
|
|
20
20
|
# command: bin/rails test test/integration test/api
|
|
21
21
|
|
|
22
|
+
# A failing suite still documents what it captured; routes reached only by
|
|
23
|
+
# failing tests are listed as uncovered. `true` aborts instead
|
|
24
|
+
# (REQCORD_STRICT=1 per run).
|
|
25
|
+
# strict: false
|
|
26
|
+
|
|
22
27
|
routes:
|
|
23
|
-
# Only routes under this prefix are documented
|
|
24
|
-
#
|
|
28
|
+
# Only routes under this prefix are documented; a list works too:
|
|
29
|
+
# prefix: [/api, /partner]
|
|
30
|
+
# Filter a single run with RESOURCE=customers,cart or VERSION=v2 instead of
|
|
31
|
+
# editing this file.
|
|
25
32
|
prefix: /api
|
|
26
33
|
|
|
27
34
|
output:
|
|
@@ -8,7 +8,11 @@ module Reqcord
|
|
|
8
8
|
# No default command: with neither `command` nor `paths` the generator
|
|
9
9
|
# falls back to `bin/rails test`, and `paths` alone must be able to win.
|
|
10
10
|
"test" => {
|
|
11
|
-
"framework" => "minitest"
|
|
11
|
+
"framework" => "minitest",
|
|
12
|
+
|
|
13
|
+
# A red suite still documents what its green tests captured; strict
|
|
14
|
+
# runs abort instead, for CI that treats the docs as an artifact.
|
|
15
|
+
"strict" => false
|
|
12
16
|
},
|
|
13
17
|
|
|
14
18
|
"routes" => {
|
|
@@ -123,8 +127,21 @@ module Reqcord
|
|
|
123
127
|
Array(data.dig("test", "paths")).map(&:to_s)
|
|
124
128
|
end
|
|
125
129
|
|
|
130
|
+
# Abort on a failing suite instead of documenting what was captured.
|
|
131
|
+
def strict_tests?
|
|
132
|
+
value = ENV.fetch("REQCORD_STRICT") { data.dig("test", "strict") }
|
|
133
|
+
|
|
134
|
+
[true, "true", "1"].include?(value)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# `prefix: /api` or `prefix: [/v1, /v2]`; a route under any of them is
|
|
138
|
+
# documented. Empty means every route.
|
|
139
|
+
def route_prefixes
|
|
140
|
+
Array(data.dig("routes", "prefix")).map(&:to_s).reject(&:empty?)
|
|
141
|
+
end
|
|
142
|
+
|
|
126
143
|
def route_prefix
|
|
127
|
-
|
|
144
|
+
route_prefixes.first
|
|
128
145
|
end
|
|
129
146
|
|
|
130
147
|
def output_directory
|
data/lib/reqcord/generator.rb
CHANGED
|
@@ -56,6 +56,14 @@ module Reqcord
|
|
|
56
56
|
# run can say why a request did not turn into documentation.
|
|
57
57
|
attr_reader :unmatched_paths
|
|
58
58
|
|
|
59
|
+
# Exit status of the test run, so a caller can tell a fully green run
|
|
60
|
+
# from documentation generated out of a partly failing suite.
|
|
61
|
+
attr_reader :test_status
|
|
62
|
+
|
|
63
|
+
def tests_passed?
|
|
64
|
+
test_status.nil? || test_status.success?
|
|
65
|
+
end
|
|
66
|
+
|
|
59
67
|
# Routes seen in the table but not documentable, by reason (redirect,
|
|
60
68
|
# mount). Set by collect_routes; exposed so a run can be reconciled.
|
|
61
69
|
attr_accessor :skipped_routes
|
|
@@ -161,6 +169,10 @@ module Reqcord
|
|
|
161
169
|
Reqcord.log("skipped #{skipped_total} route(s) that cannot be documented: #{reasons}")
|
|
162
170
|
end
|
|
163
171
|
|
|
172
|
+
unless tests_passed?
|
|
173
|
+
Reqcord.warn("the test run failed: routes exercised only by failing tests are listed as uncovered")
|
|
174
|
+
end
|
|
175
|
+
|
|
164
176
|
return if unmatched_paths.empty?
|
|
165
177
|
|
|
166
178
|
shown = unmatched_paths.uniq.first(5)
|
|
@@ -187,7 +199,7 @@ module Reqcord
|
|
|
187
199
|
collector = RouteCollector.new(
|
|
188
200
|
resources: resources,
|
|
189
201
|
version: version,
|
|
190
|
-
prefix: configuration.
|
|
202
|
+
prefix: configuration.route_prefixes
|
|
191
203
|
)
|
|
192
204
|
|
|
193
205
|
routes = collector.call
|
|
@@ -254,10 +266,19 @@ module Reqcord
|
|
|
254
266
|
wait_thread.value
|
|
255
267
|
end
|
|
256
268
|
|
|
269
|
+
@test_status = status
|
|
270
|
+
|
|
257
271
|
return if status.success?
|
|
258
272
|
|
|
259
|
-
|
|
260
|
-
|
|
273
|
+
if configuration.strict_tests?
|
|
274
|
+
raise GenerationError,
|
|
275
|
+
"Test suite failed while generating Reqcord documentation (test.strict is on)"
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# A red suite still tells the truth about the requests that passed;
|
|
279
|
+
# dropping everything would hide the docs behind an unrelated failure.
|
|
280
|
+
Reqcord.warn("test run exited with status #{status.exitstatus}; documenting what it captured anyway")
|
|
281
|
+
Reqcord.warn(" set test.strict: true (or REQCORD_STRICT=1) to abort on a failing suite")
|
|
261
282
|
end
|
|
262
283
|
|
|
263
284
|
def read_exchanges(capture_file)
|
|
@@ -211,10 +211,12 @@ module Reqcord
|
|
|
211
211
|
)
|
|
212
212
|
end
|
|
213
213
|
|
|
214
|
+
# `prefix` is one string or a list; nothing configured means every route.
|
|
214
215
|
def matches_prefix?(path)
|
|
215
|
-
|
|
216
|
+
prefixes = Array(prefix).map(&:to_s).reject(&:empty?)
|
|
217
|
+
return true if prefixes.empty?
|
|
216
218
|
|
|
217
|
-
path.start_with?(
|
|
219
|
+
prefixes.any? { |candidate| path.start_with?(candidate) }
|
|
218
220
|
end
|
|
219
221
|
|
|
220
222
|
# `RESOURCE=customers`, `RESOURCE=cart` (a singular resource is served by
|
data/lib/reqcord/version.rb
CHANGED
data/lib/tasks/reqcord.rake
CHANGED
|
@@ -11,31 +11,62 @@ namespace :reqcord do
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
content = <<~YAML
|
|
14
|
+
# Reqcord configuration. Every key is documented in the gem's
|
|
15
|
+
# docs/configuration.md. Precedence: environment > this file > defaults.
|
|
14
16
|
version: 1
|
|
15
17
|
|
|
16
18
|
test:
|
|
19
|
+
# minitest or rspec
|
|
17
20
|
framework: minitest
|
|
18
|
-
|
|
21
|
+
|
|
22
|
+
# The tests that exercise your API. Reqcord runs `bin/rails test <paths>`
|
|
23
|
+
# (or `rspec <paths>`) with capture enabled; a directory is enough.
|
|
24
|
+
paths:
|
|
25
|
+
- test/integration
|
|
26
|
+
|
|
27
|
+
# Or spell the command out yourself; it wins over `paths`.
|
|
28
|
+
# command: bin/rails test test/integration test/api
|
|
29
|
+
|
|
30
|
+
# A failing suite still documents what it captured. Set true to abort
|
|
31
|
+
# instead (or run with REQCORD_STRICT=1).
|
|
32
|
+
# strict: false
|
|
19
33
|
|
|
20
34
|
routes:
|
|
35
|
+
# Only routes under this prefix are documented; a list works too
|
|
36
|
+
# (`prefix: [/v1, /v2]`). Filter a single run with
|
|
37
|
+
# RESOURCE=customers,cart or VERSION=v2.
|
|
21
38
|
prefix: /api
|
|
22
39
|
|
|
23
40
|
output:
|
|
24
41
|
directory: docs/api
|
|
42
|
+
|
|
43
|
+
# Routes no test reached with a 2xx are listed in the index either
|
|
44
|
+
# way; `true` also writes a page for each of them.
|
|
25
45
|
include_uncovered: false
|
|
26
46
|
|
|
47
|
+
# markdown: pages under docs/api, curl: one runnable .sh per endpoint,
|
|
48
|
+
# postman: postman/collection.json (import into Postman or Hoppscotch).
|
|
27
49
|
exporters:
|
|
28
50
|
- curl
|
|
29
51
|
- markdown
|
|
30
52
|
- postman
|
|
31
53
|
|
|
32
54
|
variables:
|
|
55
|
+
# Host of every generated cURL and the Postman `base_url` variable.
|
|
33
56
|
base_url: http://localhost:3000
|
|
34
57
|
|
|
35
58
|
sanitize:
|
|
59
|
+
# Header values are replaced verbatim. Authorization, Cookie and
|
|
60
|
+
# X-Api-Key are always redacted, configured here or not.
|
|
36
61
|
headers:
|
|
37
62
|
Authorization: "Bearer {{token}}"
|
|
38
63
|
X-Api-Key: "{{api_key}}"
|
|
64
|
+
|
|
65
|
+
# Body keys, matched at any depth in requests and responses. password,
|
|
66
|
+
# token, access_token, api_key, secret are always redacted; add the
|
|
67
|
+
# fields your API exposes (a signed payment link, for example).
|
|
68
|
+
body:
|
|
69
|
+
password: "{{password}}"
|
|
39
70
|
YAML
|
|
40
71
|
|
|
41
72
|
File.write(path, content)
|
|
@@ -82,7 +113,7 @@ namespace :reqcord do
|
|
|
82
113
|
Reqcord::RouteCollector.call(
|
|
83
114
|
resources: ENV.fetch("RESOURCE", "").split(",").map(&:strip).reject(&:empty?),
|
|
84
115
|
version: ENV["VERSION"],
|
|
85
|
-
prefix: Reqcord.configuration.
|
|
116
|
+
prefix: Reqcord.configuration.route_prefixes
|
|
86
117
|
)
|
|
87
118
|
|
|
88
119
|
if routes.empty?
|