swagcov 0.5.0 → 0.6.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 +16 -1
- data/README.md +20 -3
- data/lib/swagcov/coverage.rb +65 -53
- data/lib/swagcov/dotfile.rb +25 -25
- data/lib/swagcov/errors.rb +8 -0
- data/lib/swagcov/openapi_files.rb +5 -5
- data/lib/swagcov/version.rb +3 -1
- data/lib/swagcov.rb +9 -9
- metadata +6 -5
- /data/lib/tasks/{swagcove.rake → swagcov.rake} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba29f88b400a4b44a37ee42725f70a5a97aa8ec9186de531ea13de33e8fec205
|
4
|
+
data.tar.gz: 6651caaa48d8fa61bd90f1598cfd3d78b8d6612ca6f14f76360ef8d85a256828
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86b8e97506c580b7981090803aa41a609d1c1396613a57da1faf7c66864c40ac0337675fa009a5c48311ceff89bf8e6f1eb683d098a0153525a71d95cdb9c124
|
7
|
+
data.tar.gz: e62b2919cb26ff819d28abf200fce58d23b7f509b47200114ce6f69bc23d086fb2399b21be6e0363a6a15102f845d6ad5dc003e5fb36f175ab1c87947b21a68a
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,21 @@
|
|
2
2
|
## main (unreleased)
|
3
3
|
-
|
4
4
|
|
5
|
+
## 0.6.0 (2025-04-09)
|
6
|
+
### Fix
|
7
|
+
- Grammatical number for endpoint(s) count output ([#78](https://github.com/smridge/swagcov/pull/78))
|
8
|
+
|
9
|
+
### Enhancement
|
10
|
+
- Add support for Rails 4.2 ([#72](https://github.com/smridge/swagcov/pull/72))
|
11
|
+
|
12
|
+
### Refactor
|
13
|
+
- `BREAKING CHANGE`: `Swagcov::BadConfigurationError` is now `Swagcov::Errors::BadConfiguration` ([#74](https://github.com/smridge/swagcov/pull/74))
|
14
|
+
- `BREAKING CHANGE`: `Swagcov::VERSION` is now `Swagcov::Version::STRING` ([#77](https://github.com/smridge/swagcov/pull/77))
|
15
|
+
- Improve path matching processing for `ignore` and `only` routes ([#65](https://github.com/smridge/swagcov/pull/65))
|
16
|
+
|
17
|
+
### Code Coverage
|
18
|
+
- Add test coverage reporting ([#68](https://github.com/smridge/swagcov/pull/68), [#69](https://github.com/smridge/swagcov/pull/69))
|
19
|
+
|
5
20
|
## 0.5.0 (2025-03-26)
|
6
21
|
### Enhancement
|
7
22
|
- Add rake task for configuration installation ([#59](https://github.com/smridge/swagcov/pull/59))
|
@@ -23,7 +38,7 @@
|
|
23
38
|
- Output width for better layout alignment ([#48](https://github.com/smridge/swagcov/pull/48))
|
24
39
|
|
25
40
|
### Code Coverage
|
26
|
-
- Added official support for ruby 3.3 and 3.4 and rails 7.1, 7.2, 8.0. See [
|
41
|
+
- Added official support for ruby 3.3 and 3.4 and rails 7.1, 7.2, 8.0. See [tests.yml](/.github/workflows/tests.yml) for detail
|
27
42
|
|
28
43
|
## 0.4.0 (2022-08-11)
|
29
44
|
- Improve OpenAPI file processing ([#26](https://github.com/smridge/swagcov/pull/26))
|
data/README.md
CHANGED
@@ -4,12 +4,30 @@
|
|
4
4
|
[](https://github.com/rubocop-hq/rubocop)
|
5
5
|
[](https://github.com/smridge/swagcov/blob/main/LICENSE)
|
6
6
|
|
7
|
+

|
8
|
+

|
9
|
+

|
10
|
+
[](https://coveralls.io/github/smridge/swagcov?branch=main)
|
11
|
+
|
7
12
|
See OpenAPI documentation coverage report for Rails Routes.
|
8
13
|
|
9
14
|
## Usages
|
10
15
|
- See overview of different endpoints covered, missing and what you choose to ignore.
|
11
16
|
- Add pass/fail to your build pipeline when missing Documentation Coverage.
|
12
17
|
|
18
|
+
## Ruby and Rails Version Support
|
19
|
+
Versioning support from a test coverage perspective, see [tests.yml](/.github/workflows/tests.yml) for detail
|
20
|
+
| `ruby -v` | `rails 4.2` | `rails 5.0` | `rails 5.1` | `rails 5.2` | `rails 6.0` | `rails 6.1` | `rails 7.0` | `rails 7.1` | `rails 7.2` | `rails 8.0` |
|
21
|
+
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
22
|
+
| `2.5` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
23
|
+
| `2.6` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
24
|
+
| `2.7` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
25
|
+
| `3.0` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
26
|
+
| `3.1` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
27
|
+
| `3.2` | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
28
|
+
| `3.3` | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
29
|
+
| `3.4` | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
30
|
+
|
13
31
|
## Installation
|
14
32
|
Add this line to your application's Gemfile:
|
15
33
|
```ruby
|
@@ -61,6 +79,8 @@ bundle exec rake swagcov:install
|
|
61
79
|
- ^/v1
|
62
80
|
ignore:
|
63
81
|
- /v1/foobar/:token
|
82
|
+
- /v1/foobar:
|
83
|
+
- GET
|
64
84
|
```
|
65
85
|
|
66
86
|
Execute:
|
@@ -108,9 +128,6 @@ bundle exec rake swagcov
|
|
108
128
|
```
|
109
129
|
<img src="https://raw.githubusercontent.com/smridge/swagcov/main/images/ignore-and-only-endpoints.png">
|
110
130
|
|
111
|
-
## TODO
|
112
|
-
- Add autogeneration of ignore paths
|
113
|
-
|
114
131
|
## Contributing
|
115
132
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for detail
|
116
133
|
|
data/lib/swagcov/coverage.rb
CHANGED
@@ -2,28 +2,31 @@
|
|
2
2
|
|
3
3
|
module Swagcov
|
4
4
|
class Coverage
|
5
|
-
attr_reader :
|
6
|
-
|
7
|
-
def initialize dotfile: Swagcov::Dotfile.new, routes: ::Rails.application.routes.routes
|
8
|
-
@total = 0
|
9
|
-
@covered = 0
|
10
|
-
@ignored = 0
|
11
|
-
@routes_not_covered = []
|
12
|
-
@routes_covered = []
|
13
|
-
@routes_ignored = []
|
5
|
+
attr_reader :data
|
6
|
+
|
7
|
+
def initialize dotfile: ::Swagcov::Dotfile.new, routes: ::Rails.application.routes.routes
|
14
8
|
@dotfile = dotfile
|
15
9
|
@routes = routes
|
10
|
+
@data = {
|
11
|
+
covered: [],
|
12
|
+
ignored: [],
|
13
|
+
uncovered: [],
|
14
|
+
total_count: 0,
|
15
|
+
covered_count: 0,
|
16
|
+
ignored_count: 0,
|
17
|
+
uncovered_count: 0
|
18
|
+
}
|
16
19
|
end
|
17
20
|
|
18
21
|
def report
|
19
22
|
collect_coverage
|
20
|
-
routes_output(@
|
21
|
-
routes_output(@
|
22
|
-
routes_output(@
|
23
|
+
routes_output(@data[:covered], "green")
|
24
|
+
routes_output(@data[:ignored], "yellow")
|
25
|
+
routes_output(@data[:uncovered], "red")
|
23
26
|
|
24
27
|
final_output
|
25
28
|
|
26
|
-
@
|
29
|
+
@data[:uncovered_count]
|
27
30
|
end
|
28
31
|
|
29
32
|
private
|
@@ -31,36 +34,36 @@ module Swagcov
|
|
31
34
|
attr_reader :dotfile
|
32
35
|
|
33
36
|
def collect_coverage
|
34
|
-
openapi_files = ::Swagcov::OpenapiFiles.new(filepaths: dotfile.
|
37
|
+
openapi_files = ::Swagcov::OpenapiFiles.new(filepaths: dotfile.docs_config)
|
38
|
+
rails_version = ::Rails::VERSION::STRING
|
35
39
|
|
36
40
|
@routes.each do |route|
|
37
41
|
path = route.path.spec.to_s.chomp("(.:format)")
|
42
|
+
verb = rails_version > "5" ? route.verb : route.verb.inspect.gsub(%r{[$^/]}, "")
|
38
43
|
|
39
|
-
next if third_party_route?(route, path)
|
44
|
+
next if third_party_route?(route, path, rails_version)
|
40
45
|
|
41
|
-
if dotfile.ignore_path?(path, verb:
|
42
|
-
|
43
|
-
@routes_ignored << { verb: route.verb, path: path, status: "ignored" }
|
46
|
+
if dotfile.ignore_path?(path, verb: verb)
|
47
|
+
update_data(:ignored, verb, path, "ignored")
|
44
48
|
next
|
45
49
|
end
|
46
50
|
|
47
51
|
next if dotfile.only_path_mismatch?(path)
|
48
52
|
|
49
|
-
@
|
53
|
+
@data[:total_count] += 1
|
50
54
|
|
51
|
-
if (response_keys = openapi_files.find_response_keys(path: path, route_verb:
|
52
|
-
|
53
|
-
@routes_covered << { verb: route.verb, path: path, status: response_keys.join(" ") }
|
55
|
+
if (response_keys = openapi_files.find_response_keys(path: path, route_verb: verb))
|
56
|
+
update_data(:covered, verb, path, response_keys.join(" "))
|
54
57
|
else
|
55
|
-
|
58
|
+
update_data(:uncovered, verb, path, "none")
|
56
59
|
end
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
60
|
-
def third_party_route? route, path
|
63
|
+
def third_party_route? route, path, rails_version
|
61
64
|
# https://github.com/rails/rails/blob/48f3c3e201b57a4832314b2c957a3b303e89bfea/actionpack/lib/action_dispatch/routing/inspector.rb#L105-L107
|
62
65
|
# Skips route paths like ["/rails/info/properties", "/rails/info", "/rails/mailers"]
|
63
|
-
route
|
66
|
+
internal_rails_route?(route, rails_version) ||
|
64
67
|
|
65
68
|
# Skips routes like "/sidekiq"
|
66
69
|
route.verb.blank? ||
|
@@ -71,6 +74,19 @@ module Swagcov
|
|
71
74
|
path.include?("/active_storage/") || path.include?("/action_mailbox/")
|
72
75
|
end
|
73
76
|
|
77
|
+
def internal_rails_route? route, rails_version
|
78
|
+
if rails_version > "5"
|
79
|
+
route.internal
|
80
|
+
else
|
81
|
+
::ActionDispatch::Routing::RouteWrapper.new(route).internal?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def update_data key, verb, path, status
|
86
|
+
@data[:"#{key}_count"] += 1
|
87
|
+
@data[key] << { verb: verb, path: path, status: status }
|
88
|
+
end
|
89
|
+
|
74
90
|
def routes_output routes, status_color
|
75
91
|
routes.each do |route|
|
76
92
|
$stdout.puts(
|
@@ -84,9 +100,9 @@ module Swagcov
|
|
84
100
|
|
85
101
|
def min_width key
|
86
102
|
strings =
|
87
|
-
@
|
88
|
-
@
|
89
|
-
@
|
103
|
+
@data[:covered].map { |hash| hash[key] } +
|
104
|
+
@data[:ignored].map { |hash| hash[key] } +
|
105
|
+
@data[:uncovered].map { |hash| hash[key] }
|
90
106
|
|
91
107
|
strings.max_by(&:length).size
|
92
108
|
end
|
@@ -96,37 +112,33 @@ module Swagcov
|
|
96
112
|
$stdout.puts(
|
97
113
|
format(
|
98
114
|
"OpenAPI documentation coverage %<percentage>.2f%% (%<covered>d/%<total>d)",
|
99
|
-
{
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
format(
|
105
|
-
"%<total>s endpoints ignored",
|
106
|
-
{ total: @ignored.to_s.yellow }
|
115
|
+
{
|
116
|
+
percentage: 100.0 * @data[:covered_count] / @data[:total_count],
|
117
|
+
covered: @data[:covered_count],
|
118
|
+
total: @data[:total_count]
|
119
|
+
}
|
107
120
|
)
|
108
121
|
)
|
109
122
|
|
110
|
-
|
111
|
-
|
112
|
-
"%<total>s endpoints checked",
|
113
|
-
{ total: @total.to_s.blue }
|
114
|
-
)
|
115
|
-
)
|
123
|
+
count_output
|
124
|
+
end
|
116
125
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
126
|
+
def count_output
|
127
|
+
{
|
128
|
+
ignored: "yellow",
|
129
|
+
total: "blue",
|
130
|
+
covered: "green",
|
131
|
+
uncovered: "red"
|
132
|
+
}.each do |key, color|
|
133
|
+
count = @data[:"#{key}_count"]
|
123
134
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
135
|
+
$stdout.puts(
|
136
|
+
format(
|
137
|
+
"%<status>s #{key} #{count == 1 ? 'endpoint' : 'endpoints'}",
|
138
|
+
{ status: count.to_s.send(color) }
|
139
|
+
)
|
128
140
|
)
|
129
|
-
|
141
|
+
end
|
130
142
|
end
|
131
143
|
end
|
132
144
|
end
|
data/lib/swagcov/dotfile.rb
CHANGED
@@ -1,22 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Swagcov
|
4
|
-
class BadConfigurationError < RuntimeError
|
5
|
-
end
|
6
|
-
|
7
4
|
class Dotfile
|
8
5
|
DEFAULT_CONFIG_FILE_NAME = ".swagcov.yml"
|
9
6
|
|
10
7
|
def initialize pathname: ::Rails.root.join(DEFAULT_CONFIG_FILE_NAME)
|
11
8
|
@dotfile = load_yaml(pathname)
|
12
9
|
|
13
|
-
raise
|
10
|
+
raise ::Swagcov::Errors::BadConfiguration, "Invalid config file (#{DEFAULT_CONFIG_FILE_NAME})" unless valid?
|
11
|
+
|
12
|
+
@ignored_regex = path_config_regex(ignored_config)
|
13
|
+
@only_regex = path_config_regex(only_config)
|
14
14
|
end
|
15
15
|
|
16
16
|
def ignore_path? path, verb:
|
17
|
-
|
17
|
+
return false unless @ignored_config
|
18
18
|
|
19
|
-
|
19
|
+
ignore_all_path_actions = @ignored_regex.match?(path)
|
20
|
+
|
21
|
+
ignored_verbs = @ignored_config.find { |config| config[path] }
|
20
22
|
|
21
23
|
return ignore_all_path_actions unless ignored_verbs.is_a?(::Hash)
|
22
24
|
|
@@ -24,11 +26,19 @@ module Swagcov
|
|
24
26
|
end
|
25
27
|
|
26
28
|
def only_path_mismatch? path
|
27
|
-
|
29
|
+
@only_config && !@only_regex.match?(path)
|
30
|
+
end
|
31
|
+
|
32
|
+
def docs_config
|
33
|
+
@docs_config ||= dotfile.dig("docs", "paths")
|
34
|
+
end
|
35
|
+
|
36
|
+
def ignored_config
|
37
|
+
@ignored_config ||= dotfile.dig("routes", "paths", "ignore")
|
28
38
|
end
|
29
39
|
|
30
|
-
def
|
31
|
-
dotfile.dig("
|
40
|
+
def only_config
|
41
|
+
@only_config ||= dotfile.dig("routes", "paths", "only")
|
32
42
|
end
|
33
43
|
|
34
44
|
private
|
@@ -36,23 +46,13 @@ module Swagcov
|
|
36
46
|
attr_reader :dotfile
|
37
47
|
|
38
48
|
def load_yaml pathname
|
39
|
-
|
49
|
+
unless pathname.exist?
|
50
|
+
raise ::Swagcov::Errors::BadConfiguration, "Missing config file (#{DEFAULT_CONFIG_FILE_NAME})"
|
51
|
+
end
|
40
52
|
|
41
|
-
YAML.load_file(pathname)
|
53
|
+
::YAML.load_file(pathname)
|
42
54
|
rescue Psych::SyntaxError
|
43
|
-
raise
|
44
|
-
end
|
45
|
-
|
46
|
-
def ignored_regex
|
47
|
-
@ignored_regex ||= path_config_regex(ignored_config)
|
48
|
-
end
|
49
|
-
|
50
|
-
def ignored_config
|
51
|
-
@ignored_config ||= dotfile.dig("routes", "paths", "ignore")
|
52
|
-
end
|
53
|
-
|
54
|
-
def only_regex
|
55
|
-
@only_regex ||= path_config_regex(dotfile.dig("routes", "paths", "only"))
|
55
|
+
raise ::Swagcov::Errors::BadConfiguration, "Malinformed config file (#{DEFAULT_CONFIG_FILE_NAME})"
|
56
56
|
end
|
57
57
|
|
58
58
|
def path_config_regex path_config
|
@@ -71,7 +71,7 @@ module Swagcov
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def valid?
|
74
|
-
dotfile &&
|
74
|
+
dotfile && docs_config
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
@@ -9,7 +9,7 @@ module Swagcov
|
|
9
9
|
|
10
10
|
def find_response_keys path:, route_verb:
|
11
11
|
# replace :id with {id}
|
12
|
-
regex = Regexp.new("^#{path.gsub(%r{:[^/]+}, '\\{[^/]+\\}')}?$")
|
12
|
+
regex = ::Regexp.new("^#{path.gsub(%r{:[^/]+}, '\\{[^/]+\\}')}?$")
|
13
13
|
|
14
14
|
matching_paths_key = @openapi_paths.keys.grep(regex).first
|
15
15
|
matching_request_method_key = @openapi_paths.dig(matching_paths_key, route_verb.downcase)
|
@@ -20,15 +20,15 @@ module Swagcov
|
|
20
20
|
private
|
21
21
|
|
22
22
|
def load_yamls
|
23
|
-
Dir.glob(@filepaths).reduce({}) do |hash, filepath|
|
23
|
+
::Dir.glob(@filepaths).reduce({}) do |hash, filepath|
|
24
24
|
hash.merge(load_yaml(filepath))
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def load_yaml filepath
|
29
|
-
YAML.load_file(filepath)["paths"]
|
30
|
-
rescue Psych::SyntaxError
|
31
|
-
raise
|
29
|
+
::YAML.load_file(filepath)["paths"]
|
30
|
+
rescue ::Psych::SyntaxError
|
31
|
+
raise ::Swagcov::Errors::BadConfiguration, "Malinformed openapi file (#{filepath})"
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
data/lib/swagcov/version.rb
CHANGED
data/lib/swagcov.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
4
|
-
|
5
|
-
if defined?(Rails)
|
6
|
-
require "swagcov/railtie"
|
7
|
-
require "swagcov/dotfile"
|
8
|
-
require "swagcov/coverage"
|
9
|
-
require "swagcov/openapi_files"
|
10
|
-
require "swagcov/install"
|
11
|
-
end
|
3
|
+
require "rails"
|
4
|
+
require "active_support/core_ext"
|
12
5
|
|
13
6
|
require "swagcov/core_ext/string"
|
7
|
+
require "swagcov/coverage"
|
8
|
+
require "swagcov/dotfile"
|
9
|
+
require "swagcov/errors"
|
10
|
+
require "swagcov/install"
|
11
|
+
require "swagcov/openapi_files"
|
12
|
+
require "swagcov/railtie"
|
13
|
+
require "swagcov/version"
|
14
14
|
|
15
15
|
module Swagcov
|
16
16
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swagcov
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sarah Ridge
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-04-09 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: rails
|
@@ -15,14 +15,14 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - ">="
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: '
|
18
|
+
version: '4.2'
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: '
|
25
|
+
version: '4.2'
|
26
26
|
email:
|
27
27
|
- sarahmarie@hey.com
|
28
28
|
executables: []
|
@@ -37,12 +37,13 @@ files:
|
|
37
37
|
- lib/swagcov/core_ext/string.rb
|
38
38
|
- lib/swagcov/coverage.rb
|
39
39
|
- lib/swagcov/dotfile.rb
|
40
|
+
- lib/swagcov/errors.rb
|
40
41
|
- lib/swagcov/install.rb
|
41
42
|
- lib/swagcov/openapi_files.rb
|
42
43
|
- lib/swagcov/railtie.rb
|
43
44
|
- lib/swagcov/version.rb
|
45
|
+
- lib/tasks/swagcov.rake
|
44
46
|
- lib/tasks/swagcov/install.rake
|
45
|
-
- lib/tasks/swagcove.rake
|
46
47
|
homepage: https://github.com/smridge/swagcov
|
47
48
|
licenses:
|
48
49
|
- MIT
|
File without changes
|