swagcov 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a764a7d06c6d8217807646056aa78f72a0a1bec7c289c3eea9f1fc49fc118d44
4
- data.tar.gz: a5b592e359fc41b8dbd7ddb692d7f8b656bba1474c5b397159a5b0a32a096040
3
+ metadata.gz: 5aaf6a7a919c70669dc24a129159b2ce961aa237495d57cfd1d94350bbad526f
4
+ data.tar.gz: e312bf832ceca1bc66017b131c958ab9f70ea4efddc32fac9bda0fcb369d7696
5
5
  SHA512:
6
- metadata.gz: 1add2c26c08559ccc88a42739747676176b0c0d86e18c6086fceeaf82f44f418f1c63a7bb840a5d954be79a93d187d14a84a04a2e09059242bbeed27738beed7
7
- data.tar.gz: c15c67b17352ffc5be4fa6b4ae585647f9b217eb5620d9f534e9b1ab8903dbd859bbe656dc473f5e046dfc5f5f69265eba4b1b27f6dce426aa1ff374ee8d2949
6
+ metadata.gz: 14de18f74737e418b16153aea8c9f107545b9445fc5956dd0617ddbae4a0ad78be83017d6df8f442724186d38fd44a47b8462d4dc7ce2590c2b7aae26aaff201
7
+ data.tar.gz: b22dc442442935535df66b494d9f24f4475517eb36468208d24a3ad3b43f49202eb6ada1679efc1657804ea2e789b62b8dac030009ad1bf282fc9b6b3cfa1853
data/README.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Swagcov
2
- See coverage report for openapi docs for Rails Routes.
2
+ [![Gem Version](https://img.shields.io/gem/v/swagcov)](https://rubygems.org/gems/swagcov)
3
+ ![Gem Downloads](https://img.shields.io/gem/dt/swagcov)
4
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop-hq/rubocop)
5
+ [![GitHub License](https://img.shields.io/github/license/smridge/swagcov.svg)](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
- - Add specs
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>
@@ -2,37 +2,51 @@
2
2
 
3
3
  module Swagcov
4
4
  class Coverage
5
- def initialize
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
- Rails.application.routes.routes.each do |route|
16
- # https://github.com/rails/rails/blob/48f3c3e201b57a4832314b2c957a3b303e89bfea/actionpack/lib/action_dispatch/routing/inspector.rb#L105-L107
17
- # Skips route paths like ["/rails/info/properties", "/rails/info", "/rails/mailers"]
18
- next if route.internal
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
- # Skips routes like "/sidekiq"
21
- next unless route.verb.present?
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 ignore_path?(path)
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("#{path.gsub(%r{:[^/]+}, '\\{[^/]+\\}')}(\\.[^/]+)?$")
35
- matching_keys = docs_paths.keys.select { |k| regex.match?(k) }
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["docs"]["paths"]).reduce({}) do |acc, docspath|
60
- acc.merge(YAML.load_file(docspath)["paths"])
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
- private
65
-
66
- def ignore_path? path
67
- ignored_regex&.match?(path)
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 ignored_regex
71
- @ignored_regex ||= path_config_regex(dotfile.dig("routes", "paths", "ignore"))
72
- end
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
- def only_regex
79
- @only_regex ||= path_config_regex(dotfile.dig("routes", "paths", "only"))
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
- /#{config.join('|')}/
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 %<path>-90s %<status>s",
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Swagcov
4
- VERSION = "0.2.2"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/swagcov.rb CHANGED
@@ -4,6 +4,7 @@ require "swagcov/version"
4
4
 
5
5
  if defined?(Rails)
6
6
  require "swagcov/railtie"
7
+ require "swagcov/dotfile"
7
8
  require "swagcov/coverage"
8
9
  end
9
10
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  desc "check documentation coverage for endpoints"
4
4
  task swagcov: :environment do
5
- Swagcov::Coverage.new.report
5
+ exit Swagcov::Coverage.new.report
6
6
  end
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.2.2
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: 2021-04-22 00:00:00.000000000 Z
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.3
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