swagcov 0.2.4 → 0.4.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/README.md +75 -11
- data/lib/swagcov/coverage.rb +37 -33
- data/lib/swagcov/dotfile.rb +13 -5
- data/lib/swagcov/openapi_files.rb +34 -0
- data/lib/swagcov/version.rb +1 -1
- data/lib/swagcov.rb +1 -0
- data/lib/tasks/swagcove.rake +1 -1
- metadata +33 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8aec9444a5e8dfd1d4b23fc61c710d4ccc28d5c7985df0fbef5e8c02e16e7519
|
4
|
+
data.tar.gz: a19a3c8f73ad9efb814ff7469b6306bacb52d296893130b7fb42740d1d7e7db4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc64199a92c0322fe3c42bbaa882d103a9a8f18e1c3dbe02ddb5b56bb21d13eae763536fbcdb2f84aa8a045fb6d92726f1a953eaa27595118cbe6a7324dd5c2a
|
7
|
+
data.tar.gz: 9713fa38210e7f6273e2f9004a7dc791994ebd80e50e0852381de005f67b1c238ce995060c3643b2b1db7520d46687defa554067e3ff2a75ae71ec70a809f496
|
data/README.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Swagcov
|
2
|
-
|
2
|
+
[](https://rubygems.org/gems/swagcov)
|
3
|
+

|
4
|
+
[](https://github.com/rubocop-hq/rubocop)
|
5
|
+
[](https://github.com/smridge/swagcov/blob/main/LICENSE)
|
6
|
+
|
7
|
+
See OpenAPI documentation coverage report for Rails Routes.
|
8
|
+
|
9
|
+
## Usages
|
10
|
+
- See overview of different endpoints covered, missing and what you choose to ignore.
|
11
|
+
- Add pass/fail to your build pipeline when missing Documentation Coverage.
|
3
12
|
|
4
13
|
## Installation
|
5
14
|
Add this line to your application's Gemfile:
|
@@ -17,7 +26,7 @@ Create a `.swagcov.yml` in root of your Rails application.
|
|
17
26
|
```yml
|
18
27
|
docs:
|
19
28
|
paths:
|
20
|
-
- swagger
|
29
|
+
- swagger.yaml
|
21
30
|
```
|
22
31
|
|
23
32
|
- Add `only` routes (**optional**) :
|
@@ -34,14 +43,13 @@ Create a `.swagcov.yml` in root of your Rails application.
|
|
34
43
|
paths:
|
35
44
|
ignore:
|
36
45
|
- /v1/foobar/:token
|
37
|
-
- /sidekiq
|
38
46
|
```
|
39
47
|
|
40
|
-
- Example `.swagcov.yml` Config File:
|
48
|
+
- Full Example `.swagcov.yml` Config File:
|
41
49
|
```yml
|
42
50
|
docs:
|
43
51
|
paths:
|
44
|
-
- swagger
|
52
|
+
- swagger.yaml
|
45
53
|
|
46
54
|
routes:
|
47
55
|
paths:
|
@@ -49,7 +57,6 @@ Create a `.swagcov.yml` in root of your Rails application.
|
|
49
57
|
- ^/v1
|
50
58
|
ignore:
|
51
59
|
- /v1/foobar/:token
|
52
|
-
- /sidekiq
|
53
60
|
```
|
54
61
|
|
55
62
|
Execute:
|
@@ -57,6 +64,44 @@ Execute:
|
|
57
64
|
bundle exec rake swagcov
|
58
65
|
```
|
59
66
|
|
67
|
+
### Example configurations and output from running `bundle exec rake swagcov` from the root of your Rails Application:
|
68
|
+
- All Routes (minimal configuration):
|
69
|
+
```yml
|
70
|
+
docs:
|
71
|
+
paths:
|
72
|
+
- swagger.yaml
|
73
|
+
```
|
74
|
+
<img src="https://raw.githubusercontent.com/smridge/swagcov/main/images/all-endpoints.png">
|
75
|
+
|
76
|
+
|
77
|
+
- With `only` endpoint configuration:
|
78
|
+
```yml
|
79
|
+
docs:
|
80
|
+
paths:
|
81
|
+
- swagger.yaml
|
82
|
+
|
83
|
+
routes:
|
84
|
+
paths:
|
85
|
+
only:
|
86
|
+
- ^/v2
|
87
|
+
```
|
88
|
+
<img src="https://raw.githubusercontent.com/smridge/swagcov/main/images/only-endpoints.png">
|
89
|
+
|
90
|
+
- With `ignore` and `only` endpoint configurations:
|
91
|
+
```yml
|
92
|
+
docs:
|
93
|
+
paths:
|
94
|
+
- swagger.yaml
|
95
|
+
|
96
|
+
routes:
|
97
|
+
paths:
|
98
|
+
only:
|
99
|
+
- ^/v2
|
100
|
+
ignore:
|
101
|
+
- /v2/users
|
102
|
+
```
|
103
|
+
<img src="https://raw.githubusercontent.com/smridge/swagcov/main/images/ignore-and-only-endpoints.png">
|
104
|
+
|
60
105
|
## Development
|
61
106
|
```shell
|
62
107
|
git clone git@github.com:smridge/swagcov.git
|
@@ -72,22 +117,41 @@ gem "swagcov", path: "../swagcov"
|
|
72
117
|
bundle
|
73
118
|
```
|
74
119
|
|
120
|
+
Run Tests
|
121
|
+
```
|
122
|
+
bundle exec rspec spec --exclude-pattern spec/sandbox_**/**/*_spec.rb
|
123
|
+
```
|
124
|
+
|
125
|
+
### Test via Sandbox Application
|
126
|
+
- Go to any sandbox application within the `spec` directory
|
127
|
+
- For example, `cd spec/sandbox_5_2/`
|
128
|
+
- Install the ruby version specified in `.ruby-version` file
|
129
|
+
- Install gems: `bundle install`
|
130
|
+
- Run tests: `bundle exec rspec spec`
|
131
|
+
- Run `bundle exec rake swagcov`
|
132
|
+
- This will run against any changes made to your branch.
|
133
|
+
|
75
134
|
## Publish (internal)
|
76
135
|
> Note: Publishing a new version of this gem is only meant for maintainers.
|
77
136
|
- Ensure you have access to publish on [rubygems](https://rubygems.org/gems/swagcov).
|
78
137
|
- Update [CHANGELOG](https://github.com/smridge/swagcov/blob/main/CHANGELOG.md).
|
79
138
|
- Update [`VERSION`](https://github.com/smridge/swagcov/blob/main/lib/swagcov/version.rb).
|
80
|
-
-
|
139
|
+
- Run `bundle update` for each sandbox application to reflect new swagcov version in each `Gemfile.lock`
|
140
|
+
- Open a Pull Request to ensure all specs pass, then merge to `main`.
|
141
|
+
- Checkout the latest `main` on your machine.
|
81
142
|
- Run: `rake release`
|
82
143
|
- This command builds the gem, creates a tag and publishes to rubygems, see [bundler docs](https://bundler.io/guides/creating_gem.html#releasing-the-gem).
|
83
144
|
|
84
145
|
## TODO
|
85
|
-
-
|
86
|
-
- Test against different rails versions
|
87
|
-
- Create Sandbox Apps for Rails 5 & 6
|
146
|
+
- Create Rails 7 / Ruby 3.1 Sandbox
|
88
147
|
- Add autogeneration of ignore paths
|
89
148
|
- Add `CONTRIBUTING.md`
|
90
|
-
- Add GitHub
|
149
|
+
- Add GitHub Action for linting
|
91
150
|
|
92
151
|
## Credit
|
93
152
|
To [@lonelyelk](https://github.com/lonelyelk) for initial development!
|
153
|
+
|
154
|
+
## Contributors
|
155
|
+
<a href="https://github.com/smridge/swagcov/graphs/contributors">
|
156
|
+
<img src="https://contrib.rocks/image?repo=smridge/swagcov" />
|
157
|
+
</a>
|
data/lib/swagcov/coverage.rb
CHANGED
@@ -2,31 +2,41 @@
|
|
2
2
|
|
3
3
|
module Swagcov
|
4
4
|
class Coverage
|
5
|
-
|
5
|
+
attr_reader :total, :covered, :ignored, :routes_not_covered, :routes_covered, :routes_ignored
|
6
|
+
|
7
|
+
def initialize dotfile: Swagcov::Dotfile.new, routes: ::Rails.application.routes.routes
|
6
8
|
@total = 0
|
7
9
|
@covered = 0
|
8
10
|
@ignored = 0
|
9
11
|
@routes_not_covered = []
|
10
12
|
@routes_covered = []
|
11
13
|
@routes_ignored = []
|
12
|
-
@dotfile =
|
14
|
+
@dotfile = dotfile
|
15
|
+
@routes = routes
|
13
16
|
end
|
14
17
|
|
15
18
|
def report
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
19
|
+
collect_coverage
|
20
|
+
routes_output(@routes_covered, "green")
|
21
|
+
routes_output(@routes_ignored, "yellow")
|
22
|
+
routes_output(@routes_not_covered, "red")
|
20
23
|
|
21
|
-
|
22
|
-
next unless route.verb.present?
|
24
|
+
final_output
|
23
25
|
|
24
|
-
|
26
|
+
@total - @covered
|
27
|
+
end
|
25
28
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :dotfile
|
32
|
+
|
33
|
+
def collect_coverage
|
34
|
+
openapi_files = ::Swagcov::OpenapiFiles.new(filepaths: dotfile.doc_paths)
|
35
|
+
|
36
|
+
@routes.each do |route|
|
37
|
+
path = route.path.spec.to_s.chomp("(.:format)")
|
38
|
+
|
39
|
+
next if third_party_route?(route, path)
|
30
40
|
|
31
41
|
if dotfile.ignore_path?(path)
|
32
42
|
@ignored += 1
|
@@ -37,41 +47,35 @@ module Swagcov
|
|
37
47
|
next if dotfile.only_path_mismatch?(path)
|
38
48
|
|
39
49
|
@total += 1
|
40
|
-
regex = Regexp.new("#{path.gsub(%r{:[^/]+}, '\\{[^/]+\\}')}(\\.[^/]+)?$")
|
41
|
-
matching_keys = docs_paths.keys.select { |k| regex.match?(k) }
|
42
50
|
|
43
|
-
if (
|
51
|
+
if (response_keys = openapi_files.find_response_keys(path: path, route_verb: route.verb))
|
44
52
|
@covered += 1
|
45
|
-
@routes_covered << { verb: route.verb, path: path, status:
|
53
|
+
@routes_covered << { verb: route.verb, path: path, status: response_keys.join(" ") }
|
46
54
|
else
|
47
55
|
@routes_not_covered << { verb: route.verb, path: path, status: "none" }
|
48
56
|
end
|
49
57
|
end
|
50
|
-
|
51
|
-
routes_output(@routes_covered, "green")
|
52
|
-
routes_output(@routes_ignored, "yellow")
|
53
|
-
routes_output(@routes_not_covered, "red")
|
54
|
-
|
55
|
-
final_output
|
56
|
-
|
57
|
-
exit @total - @covered
|
58
58
|
end
|
59
59
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
60
|
+
def third_party_route? route, path
|
61
|
+
# https://github.com/rails/rails/blob/48f3c3e201b57a4832314b2c957a3b303e89bfea/actionpack/lib/action_dispatch/routing/inspector.rb#L105-L107
|
62
|
+
# Skips route paths like ["/rails/info/properties", "/rails/info", "/rails/mailers"]
|
63
|
+
route.internal ||
|
65
64
|
|
66
|
-
|
65
|
+
# Skips routes like "/sidekiq"
|
66
|
+
route.verb.blank? ||
|
67
67
|
|
68
|
-
|
68
|
+
# Exclude routes that are part of the rails gem that you would not write documentation for
|
69
|
+
# https://github.com/rails/rails/tree/main/activestorage/app/controllers/active_storage
|
70
|
+
# https://github.com/rails/rails/tree/main/actionmailbox/app/controllers/action_mailbox
|
71
|
+
path.include?("/active_storage/") || path.include?("/action_mailbox/")
|
72
|
+
end
|
69
73
|
|
70
74
|
def routes_output routes, status_color
|
71
75
|
routes.each do |route|
|
72
76
|
$stdout.puts(
|
73
77
|
format(
|
74
|
-
"%<verb>10s
|
78
|
+
"%<verb>10s %<path>-90s %<status>s",
|
75
79
|
{ verb: route[:verb], path: route[:path], status: route[:status].send(status_color) }
|
76
80
|
)
|
77
81
|
)
|
data/lib/swagcov/dotfile.rb
CHANGED
@@ -5,12 +5,12 @@ module Swagcov
|
|
5
5
|
end
|
6
6
|
|
7
7
|
class Dotfile
|
8
|
-
|
9
|
-
pathname = Rails.root.join(".swagcov.yml")
|
10
|
-
raise BadConfigurationError, "Missing .swagcov.yml" unless pathname.exist?
|
8
|
+
DEFAULT_CONFIG_FILE_NAME = ".swagcov.yml"
|
11
9
|
|
12
|
-
|
13
|
-
|
10
|
+
def initialize pathname: ::Rails.root.join(DEFAULT_CONFIG_FILE_NAME)
|
11
|
+
@dotfile = load_yaml(pathname)
|
12
|
+
|
13
|
+
raise BadConfigurationError, "Invalid config file (#{DEFAULT_CONFIG_FILE_NAME})" unless valid?
|
14
14
|
end
|
15
15
|
|
16
16
|
def ignore_path? path
|
@@ -29,6 +29,14 @@ module Swagcov
|
|
29
29
|
|
30
30
|
attr_reader :dotfile
|
31
31
|
|
32
|
+
def load_yaml pathname
|
33
|
+
raise BadConfigurationError, "Missing config file (#{DEFAULT_CONFIG_FILE_NAME})" unless pathname.exist?
|
34
|
+
|
35
|
+
YAML.load_file(pathname)
|
36
|
+
rescue Psych::SyntaxError
|
37
|
+
raise BadConfigurationError, "Malinformed config file (#{DEFAULT_CONFIG_FILE_NAME})"
|
38
|
+
end
|
39
|
+
|
32
40
|
def ignored_regex
|
33
41
|
@ignored_regex ||= path_config_regex(dotfile.dig("routes", "paths", "ignore"))
|
34
42
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Swagcov
|
4
|
+
class OpenapiFiles
|
5
|
+
def initialize filepaths:
|
6
|
+
@filepaths = filepaths
|
7
|
+
@openapi_paths = load_yamls
|
8
|
+
end
|
9
|
+
|
10
|
+
def find_response_keys path:, route_verb:
|
11
|
+
# replace :id with {id}
|
12
|
+
regex = Regexp.new("^#{path.gsub(%r{:[^/]+}, '\\{[^/]+\\}')}?$")
|
13
|
+
|
14
|
+
matching_paths_key = @openapi_paths.keys.grep(regex).first
|
15
|
+
matching_request_method_key = @openapi_paths.dig(matching_paths_key, route_verb.downcase)
|
16
|
+
|
17
|
+
matching_request_method_key["responses"].keys.map(&:to_s).sort if matching_request_method_key
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def load_yamls
|
23
|
+
Dir.glob(@filepaths).reduce({}) do |hash, filepath|
|
24
|
+
hash.merge(load_yaml(filepath))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def load_yaml filepath
|
29
|
+
YAML.load_file(filepath)["paths"]
|
30
|
+
rescue Psych::SyntaxError
|
31
|
+
raise BadConfigurationError, "Malinformed openapi file (#{filepath})"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/swagcov/version.rb
CHANGED
data/lib/swagcov.rb
CHANGED
data/lib/tasks/swagcove.rake
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swagcov
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sarah Ridge
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-08-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry-byebug
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rspec
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +80,20 @@ dependencies:
|
|
66
80
|
- - ">="
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop-rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
69
97
|
description:
|
70
98
|
email:
|
71
99
|
- sarahmarie@hey.com
|
@@ -80,6 +108,7 @@ files:
|
|
80
108
|
- lib/swagcov/core_ext/string.rb
|
81
109
|
- lib/swagcov/coverage.rb
|
82
110
|
- lib/swagcov/dotfile.rb
|
111
|
+
- lib/swagcov/openapi_files.rb
|
83
112
|
- lib/swagcov/railtie.rb
|
84
113
|
- lib/swagcov/version.rb
|
85
114
|
- lib/tasks/swagcove.rake
|
@@ -91,6 +120,7 @@ metadata:
|
|
91
120
|
homepage_uri: https://github.com/smridge/swagcov
|
92
121
|
source_code_uri: https://github.com/smridge/swagcov
|
93
122
|
changelog_uri: https://github.com/smridge/swagcov/blob/main/CHANGELOG.md
|
123
|
+
rubygems_mfa_required: 'true'
|
94
124
|
post_install_message:
|
95
125
|
rdoc_options: []
|
96
126
|
require_paths:
|
@@ -106,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
136
|
- !ruby/object:Gem::Version
|
107
137
|
version: '0'
|
108
138
|
requirements: []
|
109
|
-
rubygems_version: 3.
|
139
|
+
rubygems_version: 3.2.33
|
110
140
|
signing_key:
|
111
141
|
specification_version: 4
|
112
142
|
summary: Open API docs coverage for Rails Routes
|