swagcov 0.2.2 → 0.3.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 +72 -6
- data/lib/swagcov/coverage.rb +42 -46
- data/lib/swagcov/dotfile.rb +60 -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: 5aaf6a7a919c70669dc24a129159b2ce961aa237495d57cfd1d94350bbad526f
|
4
|
+
data.tar.gz: e312bf832ceca1bc66017b131c958ab9f70ea4efddc32fac9bda0fcb369d7696
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14de18f74737e418b16153aea8c9f107545b9445fc5956dd0617ddbae4a0ad78be83017d6df8f442724186d38fd44a47b8462d4dc7ce2590c2b7aae26aaff201
|
7
|
+
data.tar.gz: b22dc442442935535df66b494d9f24f4475517eb36468208d24a3ad3b43f49202eb6ada1679efc1657804ea2e789b62b8dac030009ad1bf282fc9b6b3cfa1853
|
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:
|
@@ -34,10 +43,9 @@ 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:
|
@@ -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/v1/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,18 +117,39 @@ 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).
|
139
|
+
- Commit changes to `main` branch locally.
|
80
140
|
- Run: `rake release`
|
81
141
|
- 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).
|
82
142
|
|
83
143
|
## TODO
|
84
|
-
-
|
85
|
-
- Test against different rails versions
|
144
|
+
- Create Rails 7 / Ruby 3.1 Sandbox
|
86
145
|
- Add autogeneration of ignore paths
|
146
|
+
- Add `CONTRIBUTING.md`
|
147
|
+
- Add GitHub Action for linting
|
87
148
|
|
88
149
|
## Credit
|
89
150
|
To [@lonelyelk](https://github.com/lonelyelk) for initial development!
|
151
|
+
|
152
|
+
## Contributors
|
153
|
+
<a href="https://github.com/smridge/swagcov/graphs/contributors">
|
154
|
+
<img src="https://contrib.rocks/image?repo=smridge/swagcov" />
|
155
|
+
</a>
|
data/lib/swagcov/coverage.rb
CHANGED
@@ -2,37 +2,51 @@
|
|
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 = []
|
14
|
+
@dotfile = dotfile
|
15
|
+
@routes = routes
|
12
16
|
end
|
13
17
|
|
14
18
|
def report
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
+
collect_coverage
|
20
|
+
routes_output(@routes_covered, "green")
|
21
|
+
routes_output(@routes_ignored, "yellow")
|
22
|
+
routes_output(@routes_not_covered, "red")
|
19
23
|
|
20
|
-
|
21
|
-
|
24
|
+
final_output
|
25
|
+
|
26
|
+
@total - @covered
|
27
|
+
end
|
22
28
|
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :dotfile
|
32
|
+
|
33
|
+
def collect_coverage
|
34
|
+
@routes.each do |route|
|
23
35
|
path = route.path.spec.to_s.sub(/\(\.:format\)$/, "")
|
24
36
|
|
25
|
-
if
|
37
|
+
next if third_party_route?(route, path)
|
38
|
+
|
39
|
+
if dotfile.ignore_path?(path)
|
26
40
|
@ignored += 1
|
27
41
|
@routes_ignored << { verb: route.verb, path: path, status: "ignored" }
|
28
42
|
next
|
29
43
|
end
|
30
44
|
|
31
|
-
next if only_path_mismatch?(path)
|
45
|
+
next if dotfile.only_path_mismatch?(path)
|
32
46
|
|
33
47
|
@total += 1
|
34
|
-
regex = Regexp.new("
|
35
|
-
matching_keys = docs_paths.keys.
|
48
|
+
regex = Regexp.new("^#{path.gsub(%r{:[^/]+}, '\\{[^/]+\\}')}(\\.[^/]+)?$")
|
49
|
+
matching_keys = docs_paths.keys.grep(regex)
|
36
50
|
|
37
51
|
if (doc = docs_paths.dig(matching_keys.first, route.verb.downcase))
|
38
52
|
@covered += 1
|
@@ -41,57 +55,39 @@ module Swagcov
|
|
41
55
|
@routes_not_covered << { verb: route.verb, path: path, status: "none" }
|
42
56
|
end
|
43
57
|
end
|
44
|
-
|
45
|
-
routes_output(@routes_covered, "green")
|
46
|
-
routes_output(@routes_ignored, "yellow")
|
47
|
-
routes_output(@routes_not_covered, "red")
|
48
|
-
|
49
|
-
final_output
|
50
|
-
|
51
|
-
exit @total - @covered
|
52
|
-
end
|
53
|
-
|
54
|
-
def dotfile
|
55
|
-
@dotfile ||= YAML.load_file(Rails.root.join(".swagcov.yml"))
|
56
58
|
end
|
57
59
|
|
58
60
|
def docs_paths
|
59
|
-
@docs_paths ||= Dir.glob(dotfile
|
60
|
-
acc.merge(
|
61
|
+
@docs_paths ||= Dir.glob(dotfile.doc_paths).reduce({}) do |acc, docspath|
|
62
|
+
acc.merge(load_yaml(docspath))
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
66
|
+
def load_yaml docspath
|
67
|
+
YAML.load_file(docspath)["paths"]
|
68
|
+
rescue Psych::SyntaxError
|
69
|
+
raise BadConfigurationError, "Malinformed openapi file (#{docspath})"
|
68
70
|
end
|
69
71
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
def only_path_mismatch? path
|
75
|
-
only_regex && !only_regex.match?(path)
|
76
|
-
end
|
72
|
+
def third_party_route? route, path
|
73
|
+
# https://github.com/rails/rails/blob/48f3c3e201b57a4832314b2c957a3b303e89bfea/actionpack/lib/action_dispatch/routing/inspector.rb#L105-L107
|
74
|
+
# Skips route paths like ["/rails/info/properties", "/rails/info", "/rails/mailers"]
|
75
|
+
route.internal ||
|
77
76
|
|
78
|
-
|
79
|
-
|
80
|
-
end
|
81
|
-
|
82
|
-
def path_config_regex path_config
|
83
|
-
return unless path_config
|
84
|
-
|
85
|
-
config = path_config.map { |path| path.first == "^" ? path : "#{path}$" }
|
77
|
+
# Skips routes like "/sidekiq"
|
78
|
+
route.verb.blank? ||
|
86
79
|
|
87
|
-
|
80
|
+
# Exclude routes that are part of the rails gem that you would not write documentation for
|
81
|
+
# https://github.com/rails/rails/tree/main/activestorage/app/controllers/active_storage
|
82
|
+
# https://github.com/rails/rails/tree/main/actionmailbox/app/controllers/action_mailbox
|
83
|
+
path.include?("/active_storage/") || path.include?("/action_mailbox/")
|
88
84
|
end
|
89
85
|
|
90
86
|
def routes_output routes, status_color
|
91
87
|
routes.each do |route|
|
92
88
|
$stdout.puts(
|
93
89
|
format(
|
94
|
-
"%<verb>10s
|
90
|
+
"%<verb>10s %<path>-90s %<status>s",
|
95
91
|
{ verb: route[:verb], path: route[:path], status: route[:status].send(status_color) }
|
96
92
|
)
|
97
93
|
)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Swagcov
|
4
|
+
class BadConfigurationError < RuntimeError
|
5
|
+
end
|
6
|
+
|
7
|
+
class Dotfile
|
8
|
+
DEFAULT_CONFIG_FILE_NAME = ".swagcov.yml"
|
9
|
+
|
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
|
+
end
|
15
|
+
|
16
|
+
def ignore_path? path
|
17
|
+
ignored_regex&.match?(path)
|
18
|
+
end
|
19
|
+
|
20
|
+
def only_path_mismatch? path
|
21
|
+
only_regex && !only_regex.match?(path)
|
22
|
+
end
|
23
|
+
|
24
|
+
def doc_paths
|
25
|
+
dotfile.dig("docs", "paths")
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :dotfile
|
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
|
+
|
40
|
+
def ignored_regex
|
41
|
+
@ignored_regex ||= path_config_regex(dotfile.dig("routes", "paths", "ignore"))
|
42
|
+
end
|
43
|
+
|
44
|
+
def only_regex
|
45
|
+
@only_regex ||= path_config_regex(dotfile.dig("routes", "paths", "only"))
|
46
|
+
end
|
47
|
+
|
48
|
+
def path_config_regex path_config
|
49
|
+
return unless path_config
|
50
|
+
|
51
|
+
config = path_config.map { |path| path.first == "^" ? path : "^#{path}$" }
|
52
|
+
|
53
|
+
/#{config.join('|')}/
|
54
|
+
end
|
55
|
+
|
56
|
+
def valid?
|
57
|
+
dotfile && doc_paths
|
58
|
+
end
|
59
|
+
end
|
60
|
+
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.3.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-02-21 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
|
@@ -79,6 +107,7 @@ files:
|
|
79
107
|
- lib/swagcov.rb
|
80
108
|
- lib/swagcov/core_ext/string.rb
|
81
109
|
- lib/swagcov/coverage.rb
|
110
|
+
- lib/swagcov/dotfile.rb
|
82
111
|
- lib/swagcov/railtie.rb
|
83
112
|
- lib/swagcov/version.rb
|
84
113
|
- lib/tasks/swagcove.rake
|
@@ -90,6 +119,7 @@ metadata:
|
|
90
119
|
homepage_uri: https://github.com/smridge/swagcov
|
91
120
|
source_code_uri: https://github.com/smridge/swagcov
|
92
121
|
changelog_uri: https://github.com/smridge/swagcov/blob/main/CHANGELOG.md
|
122
|
+
rubygems_mfa_required: 'true'
|
93
123
|
post_install_message:
|
94
124
|
rdoc_options: []
|
95
125
|
require_paths:
|
@@ -105,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
135
|
- !ruby/object:Gem::Version
|
106
136
|
version: '0'
|
107
137
|
requirements: []
|
108
|
-
rubygems_version: 3.2.
|
138
|
+
rubygems_version: 3.2.32
|
109
139
|
signing_key:
|
110
140
|
specification_version: 4
|
111
141
|
summary: Open API docs coverage for Rails Routes
|