stitches 3.7.3 → 4.0.0.RC1

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: 5fa18e703222c9f9f2cc2b750cbf06a1bf9ddac8d473e6c2775d3d0cd840e59e
4
- data.tar.gz: 550563efbfc95a84ff7c9375cbd4cd6d45eff8621370780f90760ddecc4afa3e
3
+ metadata.gz: d181adb5b8ed9642468e2a8c75ab5ed2cbb01756458885410c8538c0b0a51890
4
+ data.tar.gz: 95a4105d911e4e4ebbf927d2bf87efb8bc6dfb1d2537e4f0ebc42caf8569c44d
5
5
  SHA512:
6
- metadata.gz: 0d81db63050704736cc9aaaebc3ccc0f06bcb271a36b734c195f9b5298121c18fd43c529e32ec2ba2dcf2e76c8dda411fc245d8229a4a2df21889de87dded7d7
7
- data.tar.gz: cd636756307dd9395860278f80f9fea1638ceef28105d91cc319c80db74de58809e7e6e396f1e706b123705c7905a46d0a5e3655c7c84cd077fe6eab9808c577
6
+ metadata.gz: 442b3c89184c500c7036bb06a355c0df478ea16089777d920aefc62c94dedb37ad0be40a4a46dc558509148b0f08feb335cece9e8e79ac732482977876931d99
7
+ data.tar.gz: aeaf701f19b4e8962227cccd7421f3452bf7e2dde77bfa2e7ecce735883adade7903a3392009d351e48258d2b6f231f36d36190a8e65c184e8ad5b9681d94f7f
@@ -5,9 +5,10 @@ version: 2
5
5
  jobs:
6
6
  release:
7
7
  docker:
8
- - image: circleci/ruby:2.6.3
8
+ - image: circleci/ruby:2.7.1
9
9
  steps:
10
10
  - checkout
11
+ - run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
11
12
  - run: bundle install --full-index
12
13
  - run:
13
14
  name: Artifactory login
@@ -16,14 +17,15 @@ jobs:
16
17
  - run:
17
18
  name: Build/release gem to artifactory
18
19
  command: bundle exec rake push_artifactory
19
- ruby-2.6.3-rails-5.2:
20
+ ruby-2.7.1-rails-6.0:
20
21
  docker:
21
- - image: circleci/ruby:2.6.3
22
+ - image: circleci/ruby:2.7.1
22
23
  environment:
23
- BUNDLE_GEMFILE: Gemfile.rails-5.2
24
+ BUNDLE_GEMFILE: Gemfile.rails-6.0
24
25
  working_directory: "~/stitches"
25
26
  steps:
26
27
  - checkout
28
+ - run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
27
29
  - run: bundle install --full-index
28
30
  - run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
29
31
  --format=doc
@@ -33,18 +35,19 @@ jobs:
33
35
  fi
34
36
  - run:
35
37
  name: Notify Pager Duty
36
- command: bundle exec y-notify "#eng-platform"
38
+ command: bundle exec y-notify "#devex-alerts"
37
39
  when: on_fail
38
40
  - store_test_results:
39
41
  path: "/tmp/test-results"
40
- ruby-2.5.5-rails-5.2:
42
+ ruby-2.6.6-rails-6.0:
41
43
  docker:
42
- - image: circleci/ruby:2.5.5
44
+ - image: circleci/ruby:2.6.6
43
45
  environment:
44
- BUNDLE_GEMFILE: Gemfile.rails-5.2
46
+ BUNDLE_GEMFILE: Gemfile.rails-6.0
45
47
  working_directory: "~/stitches"
46
48
  steps:
47
49
  - checkout
50
+ - run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
48
51
  - run: bundle install --full-index
49
52
  - run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
50
53
  --format=doc
@@ -54,18 +57,19 @@ jobs:
54
57
  fi
55
58
  - run:
56
59
  name: Notify Pager Duty
57
- command: bundle exec y-notify "#eng-platform"
60
+ command: bundle exec y-notify "#devex-alerts"
58
61
  when: on_fail
59
62
  - store_test_results:
60
63
  path: "/tmp/test-results"
61
- ruby-2.6.3-rails-5.1:
64
+ ruby-2.7.1-rails-5.2:
62
65
  docker:
63
- - image: circleci/ruby:2.6.3
66
+ - image: circleci/ruby:2.7.1
64
67
  environment:
65
- BUNDLE_GEMFILE: Gemfile.rails-5.1
68
+ BUNDLE_GEMFILE: Gemfile.rails-5.2
66
69
  working_directory: "~/stitches"
67
70
  steps:
68
71
  - checkout
72
+ - run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
69
73
  - run: bundle install --full-index
70
74
  - run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
71
75
  --format=doc
@@ -75,18 +79,19 @@ jobs:
75
79
  fi
76
80
  - run:
77
81
  name: Notify Pager Duty
78
- command: bundle exec y-notify "#eng-platform"
82
+ command: bundle exec y-notify "#devex-alerts"
79
83
  when: on_fail
80
84
  - store_test_results:
81
85
  path: "/tmp/test-results"
82
- ruby-2.5.5-rails-5.1:
86
+ ruby-2.6.6-rails-5.2:
83
87
  docker:
84
- - image: circleci/ruby:2.5.5
88
+ - image: circleci/ruby:2.6.6
85
89
  environment:
86
- BUNDLE_GEMFILE: Gemfile.rails-5.1
90
+ BUNDLE_GEMFILE: Gemfile.rails-5.2
87
91
  working_directory: "~/stitches"
88
92
  steps:
89
93
  - checkout
94
+ - run: bundle config stitchfix01.jfrog.io $ARTIFACTORY_USER:$ARTIFACTORY_TOKEN
90
95
  - run: bundle install --full-index
91
96
  - run: bundle exec rspec --format RspecJunitFormatter --out /tmp/test-results/rspec.xml
92
97
  --format=doc
@@ -96,7 +101,7 @@ jobs:
96
101
  fi
97
102
  - run:
98
103
  name: Notify Pager Duty
99
- command: bundle exec y-notify "#eng-platform"
104
+ command: bundle exec y-notify "#devex-alerts"
100
105
  when: on_fail
101
106
  - store_test_results:
102
107
  path: "/tmp/test-results"
@@ -107,31 +112,31 @@ workflows:
107
112
  - release:
108
113
  context: org-global
109
114
  requires:
110
- - ruby-2.6.3-rails-5.2
111
- - ruby-2.5.5-rails-5.2
112
- - ruby-2.6.3-rails-5.1
113
- - ruby-2.5.5-rails-5.1
115
+ - ruby-2.7.1-rails-6.0
116
+ - ruby-2.6.6-rails-6.0
117
+ - ruby-2.7.1-rails-5.2
118
+ - ruby-2.6.6-rails-5.2
114
119
  filters:
115
120
  tags:
116
- only: /^[0-9]+\.[0-9]+\.[0-9](\.RC\d*)?$/
121
+ only: /^[0-9]+\.[0-9]+\.[0-9]+(\.?(RC|rc)[-\.]?\d*)?$/
117
122
  branches:
118
123
  ignore: /.*/
119
- - ruby-2.6.3-rails-5.2:
124
+ - ruby-2.7.1-rails-6.0:
120
125
  context: org-global
121
126
  filters:
122
127
  tags:
123
128
  only: &1 /.*/
124
- - ruby-2.5.5-rails-5.2:
129
+ - ruby-2.6.6-rails-6.0:
125
130
  context: org-global
126
131
  filters:
127
132
  tags:
128
133
  only: *1
129
- - ruby-2.6.3-rails-5.1:
134
+ - ruby-2.7.1-rails-5.2:
130
135
  context: org-global
131
136
  filters:
132
137
  tags:
133
138
  only: *1
134
- - ruby-2.5.5-rails-5.1:
139
+ - ruby-2.6.6-rails-5.2:
135
140
  context: org-global
136
141
  filters:
137
142
  tags:
@@ -145,11 +150,11 @@ workflows:
145
150
  only:
146
151
  - master
147
152
  jobs:
148
- - ruby-2.6.3-rails-5.2:
153
+ - ruby-2.7.1-rails-6.0:
149
154
  context: org-global
150
- - ruby-2.5.5-rails-5.2:
155
+ - ruby-2.6.6-rails-6.0:
151
156
  context: org-global
152
- - ruby-2.6.3-rails-5.1:
157
+ - ruby-2.7.1-rails-5.2:
153
158
  context: org-global
154
- - ruby-2.5.5-rails-5.1:
159
+ - ruby-2.6.6-rails-5.2:
155
160
  context: org-global
@@ -8,4 +8,4 @@
8
8
  # This file uses the GitHub CODEOWNERS convention to assign PR reviewers:
9
9
  # https://help.github.com/articles/about-codeowners/
10
10
 
11
- * @brettfishman @bwebster
11
+ * @brettfishman @bwebster @stitchfix/devex
@@ -0,0 +1,7 @@
1
+ ## Problem
2
+
3
+ «Brief overview of the problem»
4
+
5
+ ## Solution
6
+
7
+ «Brief description of how you solved the problem»
data/.gitignore CHANGED
@@ -9,4 +9,5 @@ config/database.yml
9
9
  .jhw-cache
10
10
  **.orig
11
11
  Gemfile.lock
12
+ Gemfile.*.lock
12
13
  .projections.json
@@ -1 +1 @@
1
- 2.5.3
1
+ 2.7.1
@@ -1,7 +1,10 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.4.4
4
- - 2.5.1
3
+ - 2.6
4
+ - 2.7
5
5
  - ruby-head
6
6
  notifications:
7
7
  email: false
8
+ jobs:
9
+ allow_failures:
10
+ - rvm: ruby-head
@@ -1,7 +1,6 @@
1
1
  # DO NOT MODIFY - this is managed by Git Reduce in goro
2
2
  #
3
- source 'https://gem.fury.io/me/'
4
- source 'https://www.rubygems.org'
3
+ source 'https://stitchfix01.jfrog.io/stitchfix01/api/gems/eng-gems/'
5
4
 
6
5
  gemspec
7
6
 
@@ -1,7 +1,6 @@
1
1
  # DO NOT MODIFY - this is managed by Git Reduce in goro
2
2
  #
3
- source 'https://gem.fury.io/me/'
4
- source 'https://www.rubygems.org'
3
+ source 'https://stitchfix01.jfrog.io/stitchfix01/api/gems/eng-gems/'
5
4
 
6
5
  gemspec
7
6
 
@@ -0,0 +1,7 @@
1
+ # DO NOT MODIFY - this is managed by Git Reduce in goro
2
+ #
3
+ source 'https://stitchfix01.jfrog.io/stitchfix01/api/gems/eng-gems/'
4
+
5
+ gemspec
6
+
7
+ gem 'rails', '~> 6.0.0'
data/README.md CHANGED
@@ -4,13 +4,13 @@ Create Microservices in Rails by pretty much just writing regular Rails code.
4
4
 
5
5
  This gem provides:
6
6
 
7
- * transparent API key authentication.
8
- * router-level API version based on headers.
9
- * a way to document your microservice endpoints via acceptance tests.
10
- * structured errors, buildable from invalid Active Records, Exceptions, or by hand.
7
+ - transparent API key authentication.
8
+ - router-level API version based on headers.
9
+ - a way to document your microservice endpoints via acceptance tests.
10
+ - structured errors, buildable from invalid Active Records, Exceptions, or by hand.
11
11
 
12
12
  This, plus much of what you get from Rails already, means you can create a microservice Rails application by just writing the
13
- same Rails code you write today. Instead of rendering web views, you render JSON (which is built into Rails).
13
+ same Rails code you write today. Instead of rendering web views, you render JSON (which is built into Rails).
14
14
 
15
15
  ## To install
16
16
 
@@ -29,22 +29,32 @@ bundle install
29
29
  Then, set it up:
30
30
 
31
31
  ```
32
- > bin/rails generate rspec:install
33
- > bin/rails generate apitome:install
34
32
  > bin/rails generate stitches:api
35
33
  > bundle exec rake db:migrate
36
34
  ```
37
35
 
38
36
  ### Upgrading from an older version
39
37
 
40
- * If you have a version lower than 3.3.0, you need to run two generators, one of which creates a new database migration on your
41
- `api_clients` table:
38
+ - When upgrading to version 4.0.0 you may now take advantage of an in-memory cache
39
+
40
+ You can enabled it like so
41
+
42
+ ```ruby
43
+ Stitches.configure do |config|
44
+ config.max_cache_ttl = 5 # seconds
45
+ config.max_cache_size = 100 # how many keys to cache
46
+ end
47
+ ```
48
+
49
+ - If you have a version lower than 3.3.0, you need to run two generators, one of which creates a new database migration on your
50
+ `api_clients` table:
42
51
 
43
52
  ```
44
53
  > bin/rails generate stitches:add_enabled_to_api_clients
45
54
  > bin/rails generate stitches:add_deprecation
46
55
  ```
47
- * If you have a version lower than 3.6.0, you need to run one generator:
56
+
57
+ - If you have a version lower than 3.6.0, you need to run one generator:
48
58
 
49
59
  ```
50
60
  > bin/rails generate stitches:add_deprecation
@@ -61,8 +71,8 @@ class Api::V1::WidgetsController < ApiController
61
71
  if widget.valid?
62
72
  head 201
63
73
  else
64
- render json: {
65
- errors: Stitches::Errors.from_active_record_object(widget)
74
+ render json: {
75
+ errors: Stitches::Errors.from_active_record_object(widget)
66
76
  }, status: 422
67
77
  end
68
78
  end
@@ -75,44 +85,44 @@ private
75
85
  end
76
86
  ```
77
87
 
78
- If you think there's nothing special about this—you are correct. This is the vanillaest of vanilla Rails controllers, with a few
88
+ If you think there's nothing special about this—you are correct. This is the vanillaest of vanilla Rails controllers, with a few
79
89
  notable exceptions:
80
90
 
81
- * We aren't checking content type. A stitches-based microservice always uses JSON and refuses to route requests for non-JSON to
82
- you, so there's zero need to use `respond_to` and friends.
83
- * The error-building is structured and reliable.
84
- * This is an authenticated request. No request without proper authentication will be routed here, so you don't have to worry
85
- about it in your code.
86
- * This is a versioned request. While the URL will *not* contain `v1` in it, the `Accept` header will require a version and get
87
- routed here. If you make a V2, it's just a new controller and this concern is handled at the routing layer.
91
+ - We aren't checking content type. A stitches-based microservice always uses JSON and refuses to route requests for non-JSON to
92
+ you, so there's zero need to use `respond_to` and friends.
93
+ - The error-building is structured and reliable.
94
+ - This is an authenticated request. No request without proper authentication will be routed here, so you don't have to worry
95
+ about it in your code.
96
+ - This is a versioned request. While the URL will _not_ contain `v1` in it, the `Accept` header will require a version and get
97
+ routed here. If you make a V2, it's just a new controller and this concern is handled at the routing layer.
88
98
 
89
- All this means that the Rails skills of you and your team can be directly applied to building microservices. You don't have to make a bunch of boring decisions about auth, versioning, or content-types. It also means you can start deploying and creating microservices with little friction. No need to deal with a complex DSL or new programming language to get yourselves going with Microservices.
99
+ All this means that the Rails skills of you and your team can be directly applied to building microservices. You don't have to make a bunch of boring decisions about auth, versioning, or content-types. It also means you can start deploying and creating microservices with little friction. No need to deal with a complex DSL or new programming language to get yourselves going with Microservices.
90
100
 
91
101
  ## More Info
92
102
 
93
103
  See [the wiki](https://github.com/stitchfix/stitches/wiki/Setup) for how to setup stitches.
94
104
 
95
- * [Stitches Features](https://github.com/stitchfix/stitches/wiki/Features-of-Stitches) include:
105
+ - [Stitches Features](https://github.com/stitchfix/stitches/wiki/Features-of-Stitches) include:
96
106
  - Authorization via API key
97
107
  - Versioned requests via HTTP content types
98
108
  - Structured Errors
99
109
  - ISO 8601-formatted dates
100
110
  - Deprecation using the `Sunset` header
101
- * The [Generator](https://github.com/stitchfix/stitches/wiki/Generator) sets up some code in your app, so you can start writing
102
- APIs using vanilla Rails idioms:
111
+ - An optional ApiKey cache to allow mostly DB free APIs
112
+ - The [Generator](https://github.com/stitchfix/stitches/wiki/Generator) sets up some code in your app, so you can start writing
113
+ APIs using vanilla Rails idioms:
103
114
  - a "ping" controller that can validate your app is working
104
115
  - version routing based on content-type (requests for V2 use the same URL, but are serviced by a different controller)
105
116
  - An ApiClient Active Record
106
117
  - Acceptance tests that can produce API documentation as they test your app.
107
- * Stitches provides [testing support](https://github.com/stitchfix/stitches/wiki/Testing)
108
-
118
+ - Stitches provides [testing support](https://github.com/stitchfix/stitches/wiki/Testing)
109
119
 
110
120
  ## Developing
111
121
 
112
- Although `Stitches.configuration` is global, do not depend directly on that in your logic. Instead, allow all classes to receive a configuration object in their constructor. This makes the classes easier to deal with and change, without incurring much of a real cost to development. Global symbols suck, but are convenient. This is how you make the most of it.
122
+ Although `Stitches.configuration` is global, do not depend directly on that in your logic. Instead, allow all classes to receive a configuration object in their constructor. This makes the classes easier to deal with and change, without incurring much of a real cost to development. Global symbols suck, but are convenient. This is how you make the most of it.
113
123
 
114
124
  Also, the integration test does a lot of "testing the implementation", but since Rails generators are notorious for silently
115
- failing with a successful result, we have to make sure that the various `inject_into_file` calls are actually working. Do not do
125
+ failing with a successful result, we have to make sure that the various `inject_into_file` calls are actually working. Do not do
116
126
  any fancy refactors here, just keep it up to date.
117
127
 
118
128
  ---
@@ -1,4 +1,2 @@
1
1
  require 'stitches_norailtie'
2
2
  require 'stitches/railtie'
3
- # Add new stitches ruby files to the stitches_norailtie file instead of here
4
- require 'apitome'
@@ -2,7 +2,6 @@ module Stitches
2
2
  # A middleware that will skip its behavior if the path matches an allowed URL
3
3
  class AllowlistMiddleware
4
4
  def initialize(app, options={})
5
-
6
5
  @app = app
7
6
  @configuration = options[:configuration] || Stitches.configuration
8
7
  @except = options[:except] || @configuration.allowlist_regexp
@@ -0,0 +1,42 @@
1
+ require 'lru_redux'
2
+
3
+ module Stitches::ApiClientAccessWrapper
4
+
5
+ def self.fetch_for_key(key)
6
+ if cache_enabled
7
+ fetch_for_key_from_cache(key)
8
+ else
9
+ fetch_for_key_from_db(key)
10
+ end
11
+ end
12
+
13
+ def self.fetch_for_key_from_cache(key)
14
+ api_key_cache.getset(key) do
15
+ fetch_for_key_from_db(key)
16
+ end
17
+ end
18
+
19
+ def self.fetch_for_key_from_db(key)
20
+ if ::ApiClient.column_names.include?("enabled")
21
+ ::ApiClient.find_by(key: key, enabled: true)
22
+ else
23
+ ActiveSupport::Deprecation.warn('api_keys is missing "enabled" column. Run "rails g stitches:add_enabled_to_api_clients"')
24
+ ::ApiClient.find_by(key: key)
25
+ end
26
+ end
27
+
28
+ def self.clear_api_cache
29
+ api_key_cache.clear if cache_enabled
30
+ end
31
+
32
+ def self.api_key_cache
33
+ @api_key_cache ||= LruRedux::TTL::ThreadSafeCache.new(
34
+ Stitches.configuration.max_cache_size,
35
+ Stitches.configuration.max_cache_ttl,
36
+ )
37
+ end
38
+
39
+ def self.cache_enabled
40
+ Stitches.configuration.max_cache_ttl.positive?
41
+ end
42
+ end
@@ -4,7 +4,7 @@ module Stitches
4
4
  class ApiGenerator < Rails::Generators::Base
5
5
  include Rails::Generators::Migration
6
6
 
7
- source_root(File.expand_path(File.join(File.dirname(__FILE__),"generator_files")))
7
+ source_root(File.expand_path(File.join(File.dirname(__FILE__), "generator_files")))
8
8
 
9
9
  def self.next_migration_number(path)
10
10
  Time.now.utc.strftime("%Y%m%d%H%M%S")
@@ -12,14 +12,22 @@ module Stitches
12
12
 
13
13
  desc "Bootstraps your API service with a basic ping controller and spec to ensure everything is setup properly"
14
14
  def bootstrap_api
15
- inject_into_file "Gemfile", after: /^gem ['"]rails['"].*$/ do<<-GEM
15
+ gem "apitome"
16
+ gem_group :development, :test do
17
+ gem "rspec"
18
+ gem "rspec-rails"
19
+ gem "rspec_api_documentation"
20
+ end
16
21
 
17
- gem "apitome"
18
- gem "responders"
19
- gem "rspec_api_documentation", group: [ :development, :test ]
20
- gem "capybara", group: [ :development, :test ]
21
- GEM
22
+ Bundler.with_clean_env do
23
+ run "bundle install"
22
24
  end
25
+ generate "apitome:install"
26
+ generate "rspec:install"
27
+
28
+ gsub_file 'config/initializers/apitome.rb', /config.mount_at = .*$/, "config.mount_at = nil"
29
+ gsub_file 'config/initializers/apitome.rb', /config.title = .*$/, "config.title = 'Service Documentation'"
30
+
23
31
  inject_into_file "config/routes.rb", before: /^end/ do<<-ROUTES
24
32
  namespace :api do
25
33
  scope module: :v1, constraints: Stitches::ApiVersionConstraint.new(1) do
@@ -32,15 +40,14 @@ namespace :api do
32
40
  # as well as for your client to be able to validate this as well.
33
41
  end
34
42
  end
35
- api_docs = Rack::Auth::Basic.new(Apitome::Engine ) do |_,password|
43
+
44
+ api_docs = Rack::Auth::Basic.new(Apitome::Engine) do |_, password|
36
45
  password == ENV['HTTP_AUTH_PASSWORD']
37
46
  end
38
47
  mount api_docs, at: "docs"
39
48
  ROUTES
40
49
  end
41
50
 
42
- run 'bundle install'
43
-
44
51
  copy_file "app/controllers/api.rb"
45
52
  copy_file "app/controllers/api/api_controller.rb"
46
53
  copy_file "app/controllers/api/v1.rb"
@@ -53,8 +60,6 @@ mount api_docs, at: "docs"
53
60
  template "spec/features/api_spec.rb.erb", "spec/features/api_spec.rb"
54
61
  copy_file "spec/acceptance/ping_v1_spec.rb", "spec/acceptance/ping_v1_spec.rb"
55
62
 
56
- run 'bundle install'
57
-
58
63
  migration_template "db/migrate/enable_uuid_ossp_extension.rb", "db/migrate/enable_uuid_ossp_extension.rb"
59
64
  sleep 1 # allow clock to tick so we get different numbers
60
65
  migration_template "db/migrate/create_api_clients.rb", "db/migrate/create_api_clients.rb"
@@ -70,26 +75,23 @@ require 'stitches/spec'
70
75
 
71
76
  append_to_file 'spec/rails_helper.rb' do<<-RSPEC_API
72
77
  require 'rspec_api_documentation'
78
+
73
79
  RspecApiDocumentation.configure do |config|
74
- config.format = :json
75
- config.request_headers_to_include = %w(
76
- Accept
77
- Content-Type
78
- Authorization
79
- If-Modified-Since
80
- )
81
- config.response_headers_to_include = %w(
82
- Last-Modified
83
- ETag
84
- )
85
- config.api_name = "YOUR SERVICE NAME HERE"
80
+ config.format = :json
81
+ config.request_headers_to_include = %w(
82
+ Accept
83
+ Content-Type
84
+ Authorization
85
+ If-Modified-Since
86
+ )
87
+ config.response_headers_to_include = %w(
88
+ Last-Modified
89
+ ETag
90
+ )
91
+ config.api_name = "YOUR SERVICE NAME HERE"
86
92
  end
87
- RSPEC_API
93
+ RSPEC_API
88
94
  end
89
- run "rails g apitome:install"
90
- gsub_file 'config/initializers/apitome.rb', /config.mount_at = .*$/, "config.mount_at = nil"
91
- gsub_file 'config/initializers/apitome.rb', /config.title = .*$/, "config.title = 'Service Documentation'"
92
-
93
95
  end
94
96
  end
95
97
  end
@@ -20,11 +20,6 @@ module Stitches
20
20
  # ApiClient that it maps to.
21
21
  class ApiKey < Stitches::AllowlistMiddleware
22
22
 
23
- def initialize(app,options = {})
24
- super(app,options)
25
- @realm = Rails.application.class.parent.to_s
26
- end
27
-
28
23
  protected
29
24
 
30
25
  def do_call(env)
@@ -32,35 +27,40 @@ module Stitches
32
27
  if authorization
33
28
  if authorization =~ /#{@configuration.custom_http_auth_scheme}\s+key=(.*)\s*$/
34
29
  key = $1
35
-
36
- if ApiClient.column_names.include?("enabled")
37
- client = ApiClient.where(key: key, enabled: true).first
38
- else
39
- ActiveSupport::Deprecation.warn('api_keys is missing "enabled" column. Run "rails g stitches:add_enabled_to_api_clients"')
40
- client = ApiClient.where(key: key).first
41
- end
42
-
30
+ client = Stitches::ApiClientAccessWrapper.fetch_for_key(key)
43
31
  if client.present?
44
32
  env[@configuration.env_var_to_hold_api_client_primary_key] = client.id
45
33
  env[@configuration.env_var_to_hold_api_client] = client
46
34
  @app.call(env)
47
35
  else
48
- UnauthorizedResponse.new("key invalid",@realm,@configuration.custom_http_auth_scheme)
36
+ unauthorized_response("key invalid")
49
37
  end
50
38
  else
51
- UnauthorizedResponse.new("bad authorization type",@realm,@configuration.custom_http_auth_scheme)
39
+ unauthorized_response("bad authorization type")
52
40
  end
53
41
  else
54
- UnauthorizedResponse.new("no authorization header",@realm,@configuration.custom_http_auth_scheme)
42
+ unauthorized_response("no authorization header")
55
43
  end
56
44
  end
57
45
 
58
46
  private
59
47
 
60
- class UnauthorizedResponse < Rack::Response
61
- def initialize(reason,realm,custom_http_auth_scheme)
62
- super("Unauthorized - #{reason}", 401, { "WWW-Authenticate" => "#{custom_http_auth_scheme} realm=#{realm}" })
63
- end
48
+ # TODO: (jdlubrano)
49
+ # Once Rails 5 support is no longer necessary, we can simply call
50
+ # Rails.application.class.module_parent. The module_parent method
51
+ # does not exist in Rails <= 5, though, so we need to gracefully fallback
52
+ # Rails.application.class.parent for Rails versions predating Rails 6.0.0.
53
+ def rails_app_module
54
+ application_class = Rails.application.class
55
+ parent = application_class.try(:module_parent) || application_class.parent
56
+ parent.to_s
57
+ end
58
+
59
+ def unauthorized_response(reason)
60
+ status = 401
61
+ body = "Unauthorized - #{reason}"
62
+ header = { "WWW-Authenticate" => "#{@configuration.custom_http_auth_scheme} realm=#{rails_app_module}" }
63
+ Rack::Response.new(body, status, header).finish
64
64
  end
65
65
 
66
66
  end
@@ -13,6 +13,8 @@ class Stitches::Configuration
13
13
  @custom_http_auth_scheme = UnsetString.new("custom_http_auth_scheme")
14
14
  @env_var_to_hold_api_client_primary_key = NonNullString.new("env_var_to_hold_api_client_primary_key","STITCHES_API_CLIENT_ID")
15
15
  @env_var_to_hold_api_client= NonNullString.new("env_var_to_hold_api_client","STITCHES_API_CLIENT")
16
+ @max_cache_ttl = NonNullInteger.new("max_cache_ttl", 0)
17
+ @max_cache_size = NonNullInteger.new("max_cache_size", 0)
16
18
  end
17
19
 
18
20
  # A RegExp that allows URLS around the mime type and api key requirements.
@@ -39,7 +41,7 @@ class Stitches::Configuration
39
41
  @custom_http_auth_scheme = NonNullString.new("custom_http_auth_scheme",new_custom_http_auth_scheme)
40
42
  end
41
43
 
42
- # The name of the environment variable that the ApiKey middleware should use to
44
+ # The name of the environment variable that the ApiKey middleware should use to
43
45
  # place the primary key of the authenticated ApiKey. For example, if a user provides
44
46
  # the api key 1234-1234-1234-1234, and that maps to the primary key 42 in your database,
45
47
  # the environment will contain "42" in the key provided here.
@@ -59,8 +61,40 @@ class Stitches::Configuration
59
61
  @env_var_to_hold_api_client= NonNullString.new("env_var_to_hold_api_client",new_env_var_to_hold_api_client)
60
62
  end
61
63
 
64
+ def max_cache_ttl
65
+ @max_cache_ttl.to_i
66
+ end
67
+
68
+ def max_cache_ttl=(new_max_cache_ttl)
69
+ @max_cache_ttl = NonNullInteger.new("max_cache_ttl", new_max_cache_ttl)
70
+ end
71
+
72
+ def max_cache_size
73
+ @max_cache_size.to_i
74
+ end
75
+
76
+ def max_cache_size=(new_max_cache_size)
77
+ @max_cache_size = NonNullInteger.new("max_cache_size", new_max_cache_size)
78
+ end
79
+
62
80
  private
63
81
 
82
+ class NonNullInteger
83
+ def initialize(name, value)
84
+ unless value.is_a?(Integer)
85
+ raise "#{name} must be an Integer, not a #{value.class}"
86
+ end
87
+
88
+ @value = value
89
+ end
90
+
91
+ def to_i
92
+ @value
93
+ end
94
+
95
+ alias to_integer to_i
96
+ end
97
+
64
98
  class NonNullString
65
99
  def initialize(name,string)
66
100
  unless string.nil? || string.is_a?(String)
@@ -11,4 +11,14 @@ Stitches.configure do |configuration|
11
11
  # Env var that gets the primary key of the authenticated ApiKey
12
12
  # for access in your controllers, so they don't need to re-parse the header
13
13
  # configuration.env_var_to_hold_api_client_primary_key = "YOUR_ENV_VAR"
14
+
15
+ # Configures how long to cache ApiKeys in memory (In Seconds)
16
+ # A value of 0 will disable the cache entierly
17
+ # Default is 0
18
+ # configuration.max_cache_ttl = 5
19
+
20
+ # Configures how many ApiKeys to cache at one time
21
+ # This should be larger then the number of clients
22
+ # Default is 0
23
+ # configuration.max_cache_size = 100
14
24
  end
@@ -123,14 +123,22 @@ feature "general API stuff" do
123
123
  failure_message do
124
124
  correct_code,_ = evaluate_response(response)
125
125
  if correct_code
126
- "Expected WWW-Authenticate header to be 'CustomKeyAuth realm=#{Rails.application.class.parent.to_s}', but was #{response['WWW-Authenticate']}"
126
+ "Expected WWW-Authenticate header to be 'CustomKeyAuth realm=#{realm}', but was #{response['WWW-Authenticate']}"
127
127
  else
128
128
  "Expected response to be 401, but was #{response.response_code}"
129
129
  end
130
130
  end
131
131
 
132
+ def realm
133
+ <% if ::Rails::VERSION::MAJOR >= 6 -%>
134
+ Rails.application.class.module_parent.to_s
135
+ <% else %>
136
+ Rails.application.class.parent.to_s
137
+ <% end %>
138
+ end
139
+
132
140
  def evaluate_response(response)
133
- [response.response_code == 401, response.headers["WWW-Authenticate"] == "CustomKeyAuth realm=#{Rails.application.class.parent.to_s}" ]
141
+ [response.response_code == 401, response.headers["WWW-Authenticate"] == "CustomKeyAuth realm=#{realm}"]
134
142
  end
135
143
  end
136
144
  end
@@ -1,9 +1,11 @@
1
1
  require 'stitches/api_key'
2
2
  require 'stitches/valid_mime_type'
3
+ require 'stitches/api_client_access_wrapper'
3
4
 
4
5
  module Stitches
5
6
  class Railtie < Rails::Railtie
6
7
  config.app_middleware.use Stitches::ApiKey
7
8
  config.app_middleware.use Stitches::ValidMimeType
9
+
8
10
  end
9
11
  end
@@ -16,16 +16,17 @@ module Stitches
16
16
  if accept =~ %r{application/json} && accept =~ %r{version=\d+}
17
17
  @app.call(env)
18
18
  else
19
- NotAcceptableResponse.new(accept)
19
+ not_acceptable_response(accept)
20
20
  end
21
21
  end
22
22
 
23
23
  private
24
24
 
25
- class NotAcceptableResponse < Rack::Response
26
- def initialize(accept_header)
27
- super("Not Acceptable - '#{accept_header}' didn't have the right mime type or version number. We only accept application/json with a version", 406)
28
- end
25
+ def not_acceptable_response(accept_header)
26
+ status = 406
27
+ body = "Not Acceptable - '#{accept_header}' didn't have the right mime type or version number. We only accept application/json with a version"
28
+ header = { "WWW-Authenticate" => accept_header }
29
+ Rack::Response.new(body, status, header).finish
29
30
  end
30
31
 
31
32
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Stitches
2
- VERSION = '3.7.3'
4
+ VERSION = '4.0.0.RC1'
3
5
  end
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "owners": [
3
3
  {
4
- "team": "platform"
4
+ "team": "devex"
5
5
  }
6
6
  ]
7
7
  }
@@ -0,0 +1,52 @@
1
+ require 'spec_helper.rb'
2
+
3
+ module MyApp
4
+ class Application
5
+ end
6
+ end
7
+
8
+ unless defined? ApiClient
9
+ class ApiClient
10
+ def self.column_names
11
+ ["enabled"]
12
+ end
13
+ end
14
+ end
15
+
16
+ describe Stitches::ApiClientAccessWrapper do
17
+ let(:api_client) {
18
+ double(ApiClient, id: 42)
19
+ }
20
+ before do
21
+ Stitches.configuration.reset_to_defaults!
22
+ end
23
+ describe '#fetch_by_key' do
24
+ context "cache is disabled" do
25
+ before do
26
+ expect(ApiClient).to receive(:find_by).and_return(api_client).twice
27
+ end
28
+
29
+ it "fetchs object from db twice" do
30
+ expect(described_class.fetch_for_key("123").id).to eq(42)
31
+ expect(described_class.fetch_for_key("123").id).to eq(42)
32
+ end
33
+ end
34
+
35
+ context "cache is configured" do
36
+ before do
37
+ Stitches.configure do |config|
38
+ config.max_cache_ttl = 5
39
+ config.max_cache_size = 10
40
+ end
41
+
42
+ expect(ApiClient).to receive(:find_by).and_return(api_client).once
43
+ end
44
+
45
+ it "fetchs object from cache" do
46
+ expect(described_class.fetch_for_key("123").id).to eq(42)
47
+ # This should hit the cache
48
+ expect(described_class.fetch_for_key("123").id).to eq(42)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -15,10 +15,8 @@ end
15
15
 
16
16
  describe Stitches::ApiKey do
17
17
  let(:app) { double("rack app") }
18
- let(:api_clients) {
19
- [
20
- double(ApiClient, id: 42)
21
- ]
18
+ let(:api_client) {
19
+ double(ApiClient, id: 42)
22
20
  }
23
21
 
24
22
  before do
@@ -27,23 +25,27 @@ describe Stitches::ApiKey do
27
25
  fake_rails_app = MyApp::Application.new
28
26
  allow(Rails).to receive(:application).and_return(fake_rails_app)
29
27
  allow(app).to receive(:call).with(env)
30
- allow(ApiClient).to receive(:where).and_return(api_clients)
28
+ allow(ApiClient).to receive(:find_by).and_return(api_client)
29
+ Stitches::ApiClientAccessWrapper.clear_api_cache
31
30
  end
32
31
 
33
32
  subject(:middleware) { described_class.new(app, namespace: "/api") }
34
33
 
35
34
  shared_examples "an unauthorized response" do
36
35
  it "returns a 401" do
37
- expect(@response.status).to eq(401)
36
+ status, _headers, _body = @response
37
+ expect(status).to eq(401)
38
38
  end
39
39
  it "sets the proper header" do
40
- expect(@response.headers["WWW-Authenticate"]).to eq("MyAwesomeInternalScheme realm=MyApp")
40
+ _status, headers, _body = @response
41
+ expect(headers["WWW-Authenticate"]).to eq("MyAwesomeInternalScheme realm=MyApp")
41
42
  end
42
43
  it "stops the call chain preventing anything from happening" do
43
44
  expect(app).not_to have_received(:call)
44
45
  end
45
46
  it "sends a reasonable message" do
46
- expect(@response.body).to eq([expected_body])
47
+ _status, _headers, body = @response
48
+ expect(body).to eq([expected_body])
47
49
  end
48
50
  end
49
51
 
@@ -155,18 +157,17 @@ describe Stitches::ApiKey do
155
157
  end
156
158
 
157
159
  it "sets the api_client's ID in the environment" do
158
- expect(env[Stitches.configuration.env_var_to_hold_api_client_primary_key]).to eq(api_clients.first.id)
160
+ expect(env[Stitches.configuration.env_var_to_hold_api_client_primary_key]).to eq(api_client.id)
159
161
  end
160
162
 
161
163
  it "sets the api_client itself in the environment" do
162
- expect(env[Stitches.configuration.env_var_to_hold_api_client]).to eq(api_clients.first)
164
+ expect(env[Stitches.configuration.env_var_to_hold_api_client]).to eq(api_client)
163
165
  end
164
166
  end
165
167
 
166
168
  context "unauthorized responses" do
167
169
  before do
168
170
  @response = middleware.call(env)
169
- @response.finish
170
171
  end
171
172
  context "invalid key" do
172
173
  let(:env) {
@@ -175,7 +176,7 @@ describe Stitches::ApiKey do
175
176
  "HTTP_AUTHORIZATION" => "MyAwesomeInternalScheme key=foobar",
176
177
  }
177
178
  }
178
- let(:api_clients) { [] }
179
+ let(:api_client) { nil }
179
180
 
180
181
  it_behaves_like "an unauthorized response" do
181
182
  let(:expected_body) { "Unauthorized - key invalid" }
@@ -9,17 +9,23 @@ describe Stitches::Configuration do
9
9
  let(:allowlist_regexp) { %r{foo} }
10
10
  let(:custom_http_auth_scheme) { "Blah" }
11
11
  let(:env_var_to_hold_api_client_primary_key) { "FOOBAR" }
12
+ let(:max_cache_ttl) { 11 }
13
+ let(:max_cache_size) { 111 }
12
14
 
13
15
  it "can be configured globally" do
14
16
  Stitches.configure do |config|
15
17
  config.allowlist_regexp = allowlist_regexp
16
18
  config.custom_http_auth_scheme = custom_http_auth_scheme
17
19
  config.env_var_to_hold_api_client_primary_key = env_var_to_hold_api_client_primary_key
20
+ config.max_cache_ttl = max_cache_ttl
21
+ config.max_cache_size = max_cache_size
18
22
  end
19
23
 
20
24
  expect(Stitches.configuration.allowlist_regexp).to eq(allowlist_regexp)
21
25
  expect(Stitches.configuration.custom_http_auth_scheme).to eq(custom_http_auth_scheme)
22
26
  expect(Stitches.configuration.env_var_to_hold_api_client_primary_key).to eq(env_var_to_hold_api_client_primary_key)
27
+ expect(Stitches.configuration.max_cache_ttl).to eq(max_cache_ttl)
28
+ expect(Stitches.configuration.max_cache_size).to eq(max_cache_size)
23
29
  end
24
30
 
25
31
  it "defaults to nil for allowlist_regexp" do
@@ -30,6 +36,14 @@ describe Stitches::Configuration do
30
36
  expect(Stitches.configuration.env_var_to_hold_api_client_primary_key).to eq("STITCHES_API_CLIENT_ID")
31
37
  end
32
38
 
39
+ it "defaults to 0 for max_cache_ttl" do
40
+ expect(Stitches.configuration.max_cache_ttl).to eq(0)
41
+ end
42
+
43
+ it "sets a default for max_cache_size" do
44
+ expect(Stitches.configuration.max_cache_size).to eq(0)
45
+ end
46
+
33
47
  it "blows up if you try to use custom_http_auth_scheme without having set it" do
34
48
  expect {
35
49
  Stitches.configuration.custom_http_auth_scheme
@@ -102,6 +116,37 @@ describe Stitches::Configuration do
102
116
  }.not_to raise_error
103
117
  end
104
118
  end
119
+
120
+ describe "max_cache_ttl" do
121
+ let(:config) { Stitches::Configuration.new }
122
+ it "must be an integer" do
123
+ expect {
124
+ config.max_cache_ttl = ""
125
+ }.to raise_error(/max_cache_ttl must be an Integer, not a String/)
126
+ end
127
+
128
+ it "may not be nil" do
129
+ expect {
130
+ config.max_cache_ttl = nil
131
+ }.to raise_error(/max_cache_ttl must be an Integer, not a NilClass/)
132
+ end
133
+ end
134
+
135
+ describe "max_cache_size" do
136
+ let(:config) { Stitches::Configuration.new }
137
+ it "must be an integer" do
138
+ expect {
139
+ config.max_cache_size = ""
140
+ }.to raise_error(/max_cache_size must be an Integer, not a String/)
141
+ end
142
+
143
+ it "may not be nil" do
144
+ expect {
145
+ config.max_cache_size = nil
146
+ }.to raise_error(/max_cache_size must be an Integer, not a NilClass/)
147
+ end
148
+ end
149
+
105
150
  context "deprecated options we want to support for backwards compatibility" do
106
151
 
107
152
  let(:logger) { double("logger") }
@@ -5,9 +5,10 @@ require "open3"
5
5
  RSpec.describe "Adding Stitches to a New Rails App", :integration do
6
6
  let(:work_dir) { Dir.mktmpdir }
7
7
  let(:rails_app_name) { "swamp-thing" }
8
+ let(:rails_root) { Pathname(work_dir) / rails_app_name }
8
9
 
9
10
  def run(command)
10
- stdout, stderr, stat = Open3.capture3(command)
11
+ stdout, stderr, stat = Open3.capture3({ 'BUNDLE_GEMFILE' => rails_root.join('Gemfile').to_path }, command)
11
12
  success = stat.success? && stdout !~ /Could not find generator/im
12
13
 
13
14
  if ENV["DEBUG"] == 'true' || !success
@@ -37,21 +38,30 @@ RSpec.describe "Adding Stitches to a New Rails App", :integration do
37
38
  "--no-rc",
38
39
  "--skip-bundle",
39
40
  ].join(" ")
40
- FileUtils.chdir work_dir do
41
- run rails_new
42
- FileUtils.chdir rails_app_name do
43
- example.run
41
+
42
+ # Use this local version of stitches rather than the one on Rubygems
43
+ gem_path = File.expand_path("../..", File.dirname(__FILE__))
44
+ use_local_stitches = %{echo "gem 'stitches', path: '#{gem_path}'" >> Gemfile}
45
+
46
+ Bundler.with_clean_env do
47
+ FileUtils.chdir work_dir do
48
+ run rails_new
49
+
50
+ FileUtils.chdir rails_app_name do
51
+ run use_local_stitches
52
+ # It's unclear why, but on CI the gems are not found when installed
53
+ # through bundler however installing them explicitly first fixes it.
54
+ run "gem install apitome rspec-rails rspec_api_documentation"
55
+ run "bundle install"
56
+ example.run
57
+ end
44
58
  end
45
59
  end
46
60
  end
47
61
 
48
62
  it "works as described in the README" do
49
- run "bin/rails generate rspec:install"
50
- run "bin/rails generate apitome:install"
51
63
  run "bin/rails generate stitches:api"
52
64
 
53
- rails_root = Pathname(work_dir) / rails_app_name
54
-
55
65
  # Yuck! So much duplication! BUT: Rails app templates have a notoriously silent failure mode, so mostly
56
66
  # what this is doing is ensuring that the generator inserted stuff when asked and that the very basics of what happens
57
67
  # during generation are there. It's gross, and I'm sorry.
@@ -60,9 +70,7 @@ RSpec.describe "Adding Stitches to a New Rails App", :integration do
60
70
  aggregate_failures do
61
71
  expect(File.exist?(rails_root / "app" / "controllers" / "api" / "api_controller.rb")).to eq(true)
62
72
  expect(rails_root / "Gemfile").to contain_gem("apitome")
63
- expect(rails_root / "Gemfile").to contain_gem("responders")
64
73
  expect(rails_root / "Gemfile").to contain_gem("rspec_api_documentation")
65
- expect(rails_root / "Gemfile").to contain_gem("capybara")
66
74
  expect(rails_root / "config" / "routes.rb").to have_route(namespace: :api, module_scope: :v1, resource: 'ping')
67
75
  expect(rails_root / "config" / "routes.rb").to have_route(namespace: :api, module_scope: :v2, resource: 'ping')
68
76
  expect(rails_root / "config" / "routes.rb").to have_mounted_engine("Apitome::Engine")
@@ -81,11 +89,7 @@ RSpec.describe "Adding Stitches to a New Rails App", :integration do
81
89
  end
82
90
 
83
91
  it "inserts the deprecation module into ApiController" do
84
- run "bin/rails generate rspec:install"
85
- run "bin/rails generate apitome:install"
86
92
  run "bin/rails generate stitches:api"
87
-
88
- rails_root = Pathname(work_dir) / rails_app_name
89
93
  api_controller = rails_root / "app" / "controllers" / "api" / "api_controller.rb"
90
94
 
91
95
  api_controller_contents = File.read(api_controller).split(/\n/)
@@ -106,11 +110,8 @@ RSpec.describe "Adding Stitches to a New Rails App", :integration do
106
110
  end
107
111
 
108
112
  it "inserts can update old configuration" do
109
- run "bin/rails generate rspec:install"
110
- run "bin/rails generate apitome:install"
111
113
  run "bin/rails generate stitches:api"
112
114
 
113
- rails_root = Pathname(work_dir) / rails_app_name
114
115
  initializer = rails_root / "config" / "initializers" / "stitches.rb"
115
116
 
116
117
  initializer_contents = File.read(initializer).split(/\n/)
@@ -11,13 +11,15 @@ describe Stitches::ValidMimeType do
11
11
 
12
12
  shared_examples "an unacceptable response" do
13
13
  it "returns a 406" do
14
- expect(@response.status).to eq(406)
14
+ status, _headers, _body = @response
15
+ expect(status).to eq(406)
15
16
  end
16
17
  it "stops the call chain preventing anything from happening" do
17
18
  expect(app).not_to have_received(:call)
18
19
  end
19
20
  it "sends a reasonable message" do
20
- expect(@response.body.first).to match(/didn't have the right mime type or version number. We only accept application\/json/)
21
+ _status, _headers, body = @response
22
+ expect(body.first).to match(/didn't have the right mime type or version number. We only accept application\/json/)
21
23
  end
22
24
  end
23
25
 
@@ -133,7 +135,6 @@ describe Stitches::ValidMimeType do
133
135
  context "unacceptable responses" do
134
136
  before do
135
137
  @response = middleware.call(env)
136
- @response.finish
137
138
  end
138
139
  context "no header" do
139
140
  let(:env) {
@@ -20,10 +20,9 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_runtime_dependency("rails")
22
22
  s.add_runtime_dependency("pg")
23
- s.add_runtime_dependency("rspec", ">= 3")
24
- s.add_runtime_dependency("rspec-rails", "~> 3")
25
- s.add_runtime_dependency("apitome")
23
+ s.add_runtime_dependency("lru_redux")
26
24
 
25
+ s.add_development_dependency("rspec", ">= 3")
27
26
  s.add_development_dependency("rake")
28
27
  s.add_development_dependency("rspec_junit_formatter")
29
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stitches
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.3
4
+ version: 4.0.0.RC1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stitch Fix Engineering
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2019-05-16 00:00:00.000000000 Z
14
+ date: 2020-07-22 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rails
@@ -42,47 +42,33 @@ dependencies:
42
42
  - !ruby/object:Gem::Version
43
43
  version: '0'
44
44
  - !ruby/object:Gem::Dependency
45
- name: rspec
45
+ name: lru_redux
46
46
  requirement: !ruby/object:Gem::Requirement
47
47
  requirements:
48
48
  - - ">="
49
49
  - !ruby/object:Gem::Version
50
- version: '3'
50
+ version: '0'
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
55
  - - ">="
56
56
  - !ruby/object:Gem::Version
57
- version: '3'
58
- - !ruby/object:Gem::Dependency
59
- name: rspec-rails
60
- requirement: !ruby/object:Gem::Requirement
61
- requirements:
62
- - - "~>"
63
- - !ruby/object:Gem::Version
64
- version: '3'
65
- type: :runtime
66
- prerelease: false
67
- version_requirements: !ruby/object:Gem::Requirement
68
- requirements:
69
- - - "~>"
70
- - !ruby/object:Gem::Version
71
- version: '3'
57
+ version: '0'
72
58
  - !ruby/object:Gem::Dependency
73
- name: apitome
59
+ name: rspec
74
60
  requirement: !ruby/object:Gem::Requirement
75
61
  requirements:
76
62
  - - ">="
77
63
  - !ruby/object:Gem::Version
78
- version: '0'
79
- type: :runtime
64
+ version: '3'
65
+ type: :development
80
66
  prerelease: false
81
67
  version_requirements: !ruby/object:Gem::Requirement
82
68
  requirements:
83
69
  - - ">="
84
70
  - !ruby/object:Gem::Version
85
- version: '0'
71
+ version: '3'
86
72
  - !ruby/object:Gem::Dependency
87
73
  name: rake
88
74
  requirement: !ruby/object:Gem::Requirement
@@ -123,11 +109,12 @@ extensions: []
123
109
  extra_rdoc_files: []
124
110
  files:
125
111
  - ".circleci/config.yml"
112
+ - ".github/CODEOWNERS"
113
+ - ".github/PULL_REQUEST_TEMPLATE.md"
126
114
  - ".gitignore"
127
115
  - ".ruby-gemset"
128
116
  - ".ruby-version"
129
117
  - ".travis.yml"
130
- - CODEOWNERS
131
118
  - CODE_OF_CONDUCT.md
132
119
  - CONTRIBUTING.md
133
120
  - Gemfile
@@ -135,8 +122,8 @@ files:
135
122
  - Gemfile.rails-5.0
136
123
  - Gemfile.rails-5.1
137
124
  - Gemfile.rails-5.2
125
+ - Gemfile.rails-6.0
138
126
  - LICENSE.txt
139
- - PULL_REQUEST_TEMPLATE.md
140
127
  - README.md
141
128
  - Rakefile
142
129
  - build-matrix.json
@@ -144,6 +131,7 @@ files:
144
131
  - lib/stitches/add_deprecation_generator.rb
145
132
  - lib/stitches/add_enabled_to_api_clients_generator.rb
146
133
  - lib/stitches/allowlist_middleware.rb
134
+ - lib/stitches/api_client_access_wrapper.rb
147
135
  - lib/stitches/api_generator.rb
148
136
  - lib/stitches/api_key.rb
149
137
  - lib/stitches/api_version_constraint.rb
@@ -180,6 +168,7 @@ files:
180
168
  - lib/stitches/whitelisting_middleware.rb
181
169
  - lib/stitches_norailtie.rb
182
170
  - owners.json
171
+ - spec/api_client_access_wrapper_spec.rb
183
172
  - spec/api_key_spec.rb
184
173
  - spec/api_version_constraint_spec.rb
185
174
  - spec/configuration_spec.rb
@@ -208,16 +197,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
208
197
  version: '0'
209
198
  required_rubygems_version: !ruby/object:Gem::Requirement
210
199
  requirements:
211
- - - ">="
200
+ - - ">"
212
201
  - !ruby/object:Gem::Version
213
- version: '0'
202
+ version: 1.3.1
214
203
  requirements: []
215
- rubyforge_project:
216
- rubygems_version: 2.7.6
204
+ rubygems_version: 3.1.2
217
205
  signing_key:
218
206
  specification_version: 4
219
207
  summary: You'll be in stitches at how easy it is to create a service at Stitch Fix
220
208
  test_files:
209
+ - spec/api_client_access_wrapper_spec.rb
221
210
  - spec/api_key_spec.rb
222
211
  - spec/api_version_constraint_spec.rb
223
212
  - spec/configuration_spec.rb
@@ -1,21 +0,0 @@
1
- ## Problem
2
-
3
- «Brief overview of the problem»
4
-
5
- ## Solution
6
-
7
- «Brief description of how you solved the problem»
8
-
9
- ## Checklist
10
-
11
- ### Before Merging
12
-
13
- - [ ] If there is an RC on this branch, revert the version change in `version.rb`
14
-
15
- ### After Merging
16
-
17
- See the [gem release process](https://github.com/stitchfix/eng-wiki/blob/master/technical-topics/updating-gem-versions.md) for a detailed list, but the gist of it is:
18
-
19
- - [ ] Fetch `master` locally and run the applicable `rake version:*` task **on `master`** to bump the version
20
- - [ ] Run `rake release` **on `master`** to release the new version on Gemfury
21
- - [ ] Add [release notes](https://github.com/stitchfix/messaging/releases) - **this is very important in helping other engineers understand what changed in the new version**