prefab-cloud-ruby 1.8.3 → 1.8.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ddab427174fc8ee9580364b7f55becb58806d98b94968ee3d903ce67e9b01268
4
- data.tar.gz: 181cdf62f18a7c9b09846746597273230f6b13100b302ef4531693f0a3d07085
3
+ metadata.gz: 221fd3505c561f550efb45c86fcdf1ea79a7afd442ef6d2c351d9f0ce433c391
4
+ data.tar.gz: e85a75665a06ed8350e9fe6d44bc5c7462eb1d5d698f2b58a8ae2890472740e2
5
5
  SHA512:
6
- metadata.gz: 784b5d8e0229ec1e953d16a2442561a1cc67e18fc4f398f4878ac4672256892a0d6c314b06b9cd835a8309d184d47a2280d348b8afd396f977c6c57248d7c2b9
7
- data.tar.gz: '0865454d8eab0548aff23e3caa338d037babc8d9a49165424e6b8822d6a5f5b5ba67e8395752bebedb9666ff5cd3f1eac46f4d4df66abc1c8f2274770e4d634f'
6
+ metadata.gz: 34a83eabd765201e831bc00d6b4472f1b67f6eb9271f5cd77f33de7a55571acbd323f2c6ee2c8df8a3df0602f577a3a30daebe983403d0e61870a14f6bcd7b74
7
+ data.tar.gz: fc6f2e0616a62dee54415d1290d163a055391afee5ba62f158aad5d19192ebd129507305dd6cda9735bf8b184e9c7e94657f1005384907150a0049c14cc8c6fe
@@ -25,7 +25,7 @@ jobs:
25
25
  ruby-version: ['2.7', '3.0', '3.3']
26
26
 
27
27
  steps:
28
- - uses: actions/checkout@v3
28
+ - uses: actions/checkout@v4
29
29
  with:
30
30
  submodules: recursive
31
31
  - name: Set up Ruby
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.8.5 - 2024-09-27
4
+
5
+ - Fix JS bootstrapping and improve performance (#206)
6
+ - Promote `datafile` from `x_datafile` (#205)
7
+
8
+ ## 1.8.4 - 2024-09-19
9
+
10
+ - Use `stream` subdomain for SSE (#203)
11
+
3
12
  ## 1.8.3 - 2024-09-16
4
13
 
5
14
  - Add JavaScript stub & bootstrapping (#200)
data/Gemfile.lock CHANGED
@@ -62,7 +62,7 @@ GEM
62
62
  faraday (>= 0.8, < 2)
63
63
  hashie (~> 3.5, >= 3.5.2)
64
64
  oauth2 (~> 1.0)
65
- google-protobuf (3.25.3)
65
+ google-protobuf (3.25.5)
66
66
  googleapis-common-protos-types (1.14.0)
67
67
  google-protobuf (~> 3.18)
68
68
  hashie (3.6.0)
@@ -152,7 +152,7 @@ GEM
152
152
  concurrent-ruby (~> 1.0)
153
153
  uuid (2.3.9)
154
154
  macaddr (~> 1.0)
155
- webrick (1.8.1)
155
+ webrick (1.8.2)
156
156
 
157
157
  PLATFORMS
158
158
  ruby
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.8.3
1
+ 1.8.5
@@ -30,7 +30,7 @@ module Prefab
30
30
  end
31
31
 
32
32
  # this will return the actual value of confidential, use reportable_value unless you need it
33
- def unwrap
33
+ def unwrap(raw_json: false)
34
34
  raw = case @config_value.type
35
35
  when :int, :string, :double, :bool, :log_level
36
36
  @config_value.public_send(@config_value.type)
@@ -39,7 +39,11 @@ module Prefab
39
39
  when :duration
40
40
  Prefab::Duration.new(@config_value.duration.definition)
41
41
  when :json
42
- JSON.parse(@config_value.json.json)
42
+ if raw_json
43
+ @config_value.json.json
44
+ else
45
+ JSON.parse(@config_value.json.json)
46
+ end
43
47
  else
44
48
  LOG.error "Unknown type: #{@config_value.type}"
45
49
  raise "Unknown type: #{@config_value.type}"
@@ -3,50 +3,37 @@
3
3
  module Prefab
4
4
  class JavaScriptStub
5
5
  LOG = Prefab::InternalLogger.new(self)
6
+ CAMELS = {}
6
7
 
7
8
  def initialize(client = nil)
8
9
  @client = client || Prefab.instance
9
10
  end
10
11
 
11
- # Generate the JavaScript snippet to bootstrap the client SDK. This will
12
- # include the configuration values that are permitted to be sent to the
13
- # client SDK.
14
- #
15
- # If the context provided to the client SDK is not the same as the context
16
- # used to generate the configuration values, the client SDK will still
17
- # generate a fetch to get the correct values for the context.
18
- #
19
- # Any keys that could not be resolved will be logged as a warning to the
20
- # console.
21
12
  def bootstrap(context)
22
- configs, warnings = data(context)
13
+ configs, warnings = data(context, :bootstrap)
23
14
  <<~JS
24
15
  window._prefabBootstrap = {
25
- configs: #{JSON.dump(configs)},
16
+ evaluations: #{JSON.dump(configs)},
26
17
  context: #{JSON.dump(context)}
27
18
  }
28
19
  #{log_warnings(warnings)}
29
20
  JS
30
21
  end
31
22
 
32
- # Generate the JavaScript snippet to *replace* the client SDK. Use this to
33
- # get `prefab.get` and `prefab.isEnabled` functions on the window object.
34
- #
35
- # Only use this if you are not using the client SDK and do not need
36
- # client-side context.
37
- #
38
- # Any keys that could not be resolved will be logged as a warning to the
39
- # console.
40
- def generate_stub(context)
41
- configs, warnings = data(context)
23
+ def generate_stub(context, callback = nil)
24
+ configs, warnings = data(context, :stub)
42
25
  <<~JS
43
26
  window.prefab = window.prefab || {};
44
27
  window.prefab.config = #{JSON.dump(configs)};
45
28
  window.prefab.get = function(key) {
46
- return window.prefab.config[key];
29
+ var value = window.prefab.config[key];
30
+ #{callback && " #{callback}(key, value);"}
31
+ return value;
47
32
  };
48
33
  window.prefab.isEnabled = function(key) {
49
- return window.prefab.config[key] === true;
34
+ var value = window.prefab.config[key] === true;
35
+ #{callback && " #{callback}(key, value);"}
36
+ return value;
50
37
  };
51
38
  #{log_warnings(warnings)}
52
39
  JS
@@ -55,7 +42,7 @@ module Prefab
55
42
  private
56
43
 
57
44
  def underlying_value(value)
58
- v = Prefab::ConfigValueUnwrapper.new(value, @client.resolver).unwrap
45
+ v = Prefab::ConfigValueUnwrapper.new(value, @client.resolver).unwrap(raw_json: true)
59
46
  case v
60
47
  when Google::Protobuf::RepeatedField
61
48
  v.to_a
@@ -70,11 +57,11 @@ module Prefab
70
57
  return '' if warnings.empty?
71
58
 
72
59
  <<~JS
73
- console.warn('The following keys could not be resolved:', #{JSON.dump(@warnings)});
60
+ console.warn('The following keys could not be resolved:', #{JSON.dump(warnings)});
74
61
  JS
75
62
  end
76
63
 
77
- def data(context)
64
+ def data(context, mode)
78
65
  permitted = {}
79
66
  warnings = []
80
67
  resolver_keys = @client.resolver.keys
@@ -83,8 +70,13 @@ module Prefab
83
70
  begin
84
71
  config = @client.resolver.raw(key)
85
72
 
86
- if config.config_type == :FEATURE_FLAG || config.send_to_client_sdk
87
- permitted[key] = underlying_value(@client.resolver.get(key, context).value)
73
+ if config.config_type == :FEATURE_FLAG || config.send_to_client_sdk || config.config_type == :LOG_LEVEL
74
+ value = @client.resolver.get(key, context).value
75
+ if mode == :bootstrap
76
+ permitted[key] = { value: { to_camel_case(value.type) => underlying_value(value) } }
77
+ else
78
+ permitted[key] = underlying_value(value)
79
+ end
88
80
  end
89
81
  rescue StandardError => e
90
82
  LOG.warn("Could not resolve key #{key}: #{e}")
@@ -95,5 +87,13 @@ module Prefab
95
87
 
96
88
  [permitted, warnings]
97
89
  end
90
+
91
+ def to_camel_case(str)
92
+ CAMELS[str] ||= begin
93
+ str.to_s.split('_').map.with_index { |word, index|
94
+ index == 0 ? word : word.capitalize
95
+ }.join
96
+ end
97
+ end
98
98
  end
99
99
  end
@@ -66,6 +66,7 @@ module Prefab
66
66
  collect_evaluation_summaries: true,
67
67
  collect_max_evaluation_summaries: DEFAULT_MAX_EVAL_SUMMARIES,
68
68
  allow_telemetry_in_local_mode: false,
69
+ datafile: ENV['PREFAB_DATAFILE'],
69
70
  x_datafile: ENV['PREFAB_DATAFILE'],
70
71
  x_use_local_cache: false,
71
72
  global_context: {}
@@ -76,7 +77,13 @@ module Prefab
76
77
  @initialization_timeout_sec = initialization_timeout_sec
77
78
  @on_init_failure = on_init_failure
78
79
  @prefab_datasources = prefab_datasources
79
- @datafile = x_datafile
80
+
81
+ @datafile = datafile || x_datafile
82
+
83
+ if !x_datafile.nil?
84
+ warn '[DEPRECATION] x_datafile is deprecated. Please provide `datafile` instead'
85
+ end
86
+
80
87
  @prefab_config_classpath_dir = prefab_config_classpath_dir
81
88
  @prefab_config_override_dir = prefab_config_override_dir
82
89
  @prefab_envs = Array(prefab_envs)
data/lib/prefab/prefab.rb CHANGED
@@ -78,14 +78,40 @@ module Prefab
78
78
  @singleton.is_ff?(key)
79
79
  end
80
80
 
81
+ # Generate the JavaScript snippet to bootstrap the client SDK. This will
82
+ # include the configuration values that are permitted to be sent to the
83
+ # client SDK.
84
+ #
85
+ # If the context provided to the client SDK is not the same as the context
86
+ # used to generate the configuration values, the client SDK will still
87
+ # generate a fetch to get the correct values for the context.
88
+ #
89
+ # Any keys that could not be resolved will be logged as a warning to the
90
+ # console.
81
91
  def self.bootstrap_javascript(context)
82
92
  ensure_initialized
83
93
  Prefab::JavaScriptStub.new(@singleton).bootstrap(context)
84
94
  end
85
95
 
86
- def self.generate_javascript_stub(context)
96
+ # Generate the JavaScript snippet to *replace* the client SDK. Use this to
97
+ # get `prefab.get` and `prefab.isEnabled` functions on the window object.
98
+ #
99
+ # Only use this if you are not using the client SDK and do not need
100
+ # client-side context.
101
+ #
102
+ # Any keys that could not be resolved will be logged as a warning to the
103
+ # console.
104
+ #
105
+ # You can pass an optional callback function to be called with the key and
106
+ # value of each configuration value. This can be useful for logging,
107
+ # tracking experiment exposure, etc.
108
+ #
109
+ # e.g.
110
+ # - `Prefab.generate_javascript_stub(context, "reportExperimentExposure")`
111
+ # - `Prefab.generate_javascript_stub(context, "(key,value)=>{console.log({eval: 'eval', key,value})}")`
112
+ def self.generate_javascript_stub(context, callback = nil)
87
113
  ensure_initialized
88
- Prefab::JavaScriptStub.new(@singleton).generate_stub(context)
114
+ Prefab::JavaScriptStub.new(@singleton).generate_stub(context, callback)
89
115
  end
90
116
 
91
117
  private
@@ -106,7 +106,7 @@ module Prefab
106
106
  @source_index = 0
107
107
  end
108
108
 
109
- return @prefab_options.sse_sources[@source_index]
109
+ return @prefab_options.sse_sources[@source_index].sub(/(belt|suspenders)\./, 'stream.')
110
110
  end
111
111
  end
112
112
  end
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: prefab-cloud-ruby 1.8.3 ruby lib
5
+ # stub: prefab-cloud-ruby 1.8.5 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "prefab-cloud-ruby".freeze
9
- s.version = "1.8.3"
9
+ s.version = "1.8.5"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Jeff Dwyer".freeze]
14
- s.date = "2024-09-16"
14
+ s.date = "2024-09-27"
15
15
  s.description = "Feature Flags, Live Config, and Dynamic Log Levels as a service".freeze
16
16
  s.email = "jdwyer@prefab.cloud".freeze
17
17
  s.extra_rdoc_files = [
@@ -84,6 +84,7 @@ Gem::Specification.new do |s|
84
84
  "prefab-cloud-ruby.gemspec",
85
85
  "test/.prefab.default.config.yaml",
86
86
  "test/.prefab.unit_tests.config.yaml",
87
+ "test/fixtures/datafile.json",
87
88
  "test/integration_test.rb",
88
89
  "test/integration_test_helpers.rb",
89
90
  "test/support/common_helpers.rb",
@@ -0,0 +1,87 @@
1
+ {
2
+ "configs": [
3
+ {
4
+ "id": "16825372746571694",
5
+ "projectId": "202",
6
+ "key": "log-level",
7
+ "changedBy": {
8
+ "email": "jeffrey.chupp@prefab.cloud"
9
+ },
10
+ "configType": "DELETED"
11
+ },
12
+ {
13
+ "id": "17271108409487302",
14
+ "projectId": "202",
15
+ "key": "flag.list.environments",
16
+ "changedBy": {
17
+ "email": "jeffrey.chupp@prefab.cloud"
18
+ },
19
+ "rows": [
20
+ {
21
+ "projectEnvId": "308",
22
+ "values": [
23
+ {
24
+ "criteria": [
25
+ {
26
+ "propertyName": "user.key",
27
+ "operator": "PROP_IS_ONE_OF",
28
+ "valueToMatch": {
29
+ "stringList": {
30
+ "values": [
31
+ "5905ecd1-9bbf-4711-a663-4f713628a78c"
32
+ ]
33
+ }
34
+ }
35
+ }
36
+ ],
37
+ "value": {
38
+ "bool": true
39
+ }
40
+ },
41
+ {
42
+ "value": {
43
+ "bool": true
44
+ }
45
+ }
46
+ ]
47
+ }
48
+ ],
49
+ "allowableValues": [
50
+ {
51
+ "bool": false
52
+ },
53
+ {
54
+ "bool": true
55
+ }
56
+ ],
57
+ "configType": "FEATURE_FLAG",
58
+ "valueType": "BOOL"
59
+ },
60
+ {
61
+ "id": "17271831941669987",
62
+ "projectId": "202",
63
+ "key": "my.test.string",
64
+ "changedBy": {
65
+ "userId": "3",
66
+ "apiKeyId": "481"
67
+ },
68
+ "rows": [
69
+ {
70
+ "values": [
71
+ {
72
+ "value": {
73
+ "string": "hello world"
74
+ }
75
+ }
76
+ ]
77
+ }
78
+ ],
79
+ "configType": "CONFIG",
80
+ "valueType": "STRING"
81
+ }
82
+ ],
83
+ "configServicePointer": {
84
+ "projectId": "202",
85
+ "projectEnvId": "308"
86
+ }
87
+ }
data/test/test_client.rb CHANGED
@@ -427,6 +427,14 @@ class TestClient < Minitest::Test
427
427
  refute client.is_ff?('does_not_exist')
428
428
  end
429
429
 
430
+ def test_with_datafile
431
+ datafile = "#{Dir.pwd}/test/fixtures/datafile.json"
432
+ client = new_client(datafile: datafile, prefab_datasources: :all)
433
+
434
+ assert client.get('flag.list.environments')
435
+ assert_equal "hello world", client.get('my.test.string')
436
+ end
437
+
430
438
  private
431
439
 
432
440
  def basic_value_config
@@ -48,6 +48,34 @@ class JavascriptStubTest < Minitest::Test
48
48
  rows: [DEFAULT_ROW]
49
49
  )
50
50
 
51
+ json_config = PrefabProto::Config.new(
52
+ id: 234,
53
+ key: 'json-config',
54
+ config_type: PrefabProto::ConfigType::CONFIG,
55
+ send_to_client_sdk: true,
56
+ rows: [
57
+ PrefabProto::ConfigRow.new(
58
+ values: [
59
+ PrefabProto::ConditionalValue.new(value: PrefabProto::ConfigValue.new(json: PrefabProto::Json.new(json: '{"key":"value"}')))
60
+ ]
61
+ )
62
+ ]
63
+ )
64
+
65
+ duration_config = PrefabProto::Config.new(
66
+ id: 236,
67
+ key: 'duration-config',
68
+ config_type: PrefabProto::ConfigType::CONFIG,
69
+ send_to_client_sdk: true,
70
+ rows: [
71
+ PrefabProto::ConfigRow.new(
72
+ values: [
73
+ PrefabProto::ConditionalValue.new(value: PrefabProto::ConfigValue.new(duration: PrefabProto::IsoDuration.new(definition: "P4DT12H30M5S")))
74
+ ]
75
+ )
76
+ ]
77
+ )
78
+
51
79
  ff = PrefabProto::Config.new(
52
80
  id: 456,
53
81
  key: 'feature-flag',
@@ -72,7 +100,7 @@ class JavascriptStubTest < Minitest::Test
72
100
  )
73
101
 
74
102
  @client = new_client(
75
- config: [log_level, config_for_sdk, config_not_for_sdk, ff],
103
+ config: [log_level, config_for_sdk, config_not_for_sdk, ff, json_config, duration_config],
76
104
  project_env_id: PROJECT_ENV_ID,
77
105
  collect_evaluation_summaries: true,
78
106
  prefab_config_override_dir: '/tmp',
@@ -85,20 +113,29 @@ class JavascriptStubTest < Minitest::Test
85
113
  def test_bootstrap
86
114
  result = Prefab::JavaScriptStub.new(@client).bootstrap({})
87
115
 
116
+
117
+ File.open('/tmp/prefab_config.json', 'w') do |f|
118
+ f.write(result)
119
+ end
88
120
  assert_equal %(
89
121
  window._prefabBootstrap = {
90
- configs: {"basic-config":"default_value","feature-flag":false},
122
+ evaluations: {"log-level":{"value":{"logLevel":"INFO"}},"basic-config":{"value":{"string":"default_value"}},"feature-flag":{"value":{"bool":false}},"json-config":{"value":{"json":"{\\"key\\":\\"value\\"}"}},"duration-config":{"value":{"duration":{"ms":390605000.0,"seconds":390605.0}}}},
91
123
  context: {}
92
124
  }
93
125
  ).strip, result.strip
94
126
 
95
127
  result = Prefab::JavaScriptStub.new(@client).bootstrap({ user: { email: 'gmail.com' } })
96
128
 
129
+ File.open('/tmp/prefab_config.json', 'w') do |f|
130
+ f.write(result)
131
+ end
132
+
97
133
  assert_equal %(
98
134
  window._prefabBootstrap = {
99
- configs: {"basic-config":"default_value","feature-flag":true},
135
+ evaluations: {"log-level":{"value":{"logLevel":"INFO"}},"basic-config":{"value":{"string":"default_value"}},"feature-flag":{"value":{"bool":true}},"json-config":{"value":{"json":"{\\"key\\":\\"value\\"}"}},"duration-config":{"value":{"duration":{"ms":390605000.0,"seconds":390605.0}}}},
100
136
  context: {"user":{"email":"gmail.com"}}
101
137
  }
138
+
102
139
  ).strip, result.strip
103
140
  end
104
141
 
@@ -107,25 +144,33 @@ window._prefabBootstrap = {
107
144
 
108
145
  assert_equal %(
109
146
  window.prefab = window.prefab || {};
110
- window.prefab.config = {"basic-config":"default_value","feature-flag":false};
147
+ window.prefab.config = {"log-level":"INFO","basic-config":"default_value","feature-flag":false,"json-config":"{\\"key\\":\\"value\\"}","duration-config":{"ms":390605000.0,"seconds":390605.0}};
111
148
  window.prefab.get = function(key) {
112
- return window.prefab.config[key];
149
+ var value = window.prefab.config[key];
150
+
151
+ return value;
113
152
  };
114
153
  window.prefab.isEnabled = function(key) {
115
- return window.prefab.config[key] === true;
154
+ var value = window.prefab.config[key] === true;
155
+
156
+ return value;
116
157
  };
117
158
  ).strip, result.strip
118
159
 
119
- result = Prefab::JavaScriptStub.new(@client).generate_stub({ user: { email: 'gmail.com' } })
160
+ result = Prefab::JavaScriptStub.new(@client).generate_stub({ user: { email: 'gmail.com' } }, 'myEvalCallback')
120
161
 
121
162
  assert_equal %(
122
163
  window.prefab = window.prefab || {};
123
- window.prefab.config = {"basic-config":"default_value","feature-flag":true};
164
+ window.prefab.config = {"log-level":"INFO","basic-config":"default_value","feature-flag":true,"json-config":"{\\"key\\":\\"value\\"}","duration-config":{"ms":390605000.0,"seconds":390605.0}};
124
165
  window.prefab.get = function(key) {
125
- return window.prefab.config[key];
166
+ var value = window.prefab.config[key];
167
+ myEvalCallback(key, value);
168
+ return value;
126
169
  };
127
170
  window.prefab.isEnabled = function(key) {
128
- return window.prefab.config[key] === true;
171
+ var value = window.prefab.config[key] === true;
172
+ myEvalCallback(key, value);
173
+ return value;
129
174
  };
130
175
 
131
176
  ).strip, result.strip
data/test/test_options.rb CHANGED
@@ -85,4 +85,9 @@ class TestOptions < Minitest::Test
85
85
  options = Prefab::Options.new(context_upload_mode: :none)
86
86
  assert_equal 0, options.collect_max_shapes
87
87
  end
88
+
89
+ def test_loading_a_datafile
90
+ options = Prefab::Options.new(datafile: "#{Dir.pwd}/test/fixtures/datafile.json")
91
+ assert_equal "#{Dir.pwd}/test/fixtures/datafile.json", options.datafile
92
+ end
88
93
  end
@@ -6,7 +6,7 @@ require 'webrick'
6
6
  class TestSSEConfigClient < Minitest::Test
7
7
  def test_client
8
8
  sources = [
9
- 'https://api.staging-prefab.cloud/'
9
+ 'https://belt.staging-prefab.cloud/'
10
10
  ]
11
11
 
12
12
  options = Prefab::Options.new(sources: sources, api_key: ENV.fetch('PREFAB_INTEGRATION_TEST_API_KEY', nil))
@@ -16,6 +16,7 @@ class TestSSEConfigClient < Minitest::Test
16
16
  client = Prefab::SSEConfigClient.new(options, config_loader)
17
17
 
18
18
  assert_equal 4, client.headers['x-prefab-start-at-id']
19
+ assert_equal "https://stream.staging-prefab.cloud", client.source
19
20
 
20
21
  result = nil
21
22
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prefab-cloud-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.3
4
+ version: 1.8.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Dwyer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-16 00:00:00.000000000 Z
11
+ date: 2024-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -285,6 +285,7 @@ files:
285
285
  - prefab-cloud-ruby.gemspec
286
286
  - test/.prefab.default.config.yaml
287
287
  - test/.prefab.unit_tests.config.yaml
288
+ - test/fixtures/datafile.json
288
289
  - test/integration_test.rb
289
290
  - test/integration_test_helpers.rb
290
291
  - test/support/common_helpers.rb