remocon 0.1.0 → 0.2.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.
@@ -3,19 +3,10 @@
3
3
  module Remocon
4
4
  module Command
5
5
  class Push
6
- attr_reader :uri
6
+ attr_reader :config, :cmd_opts
7
7
 
8
8
  def initialize(opts)
9
- @opts = opts
10
-
11
- @project_id = ENV.fetch('FIREBASE_PROJECT_ID')
12
- @token = ENV.fetch('REMOTE_CONFIG_ACCESS_TOKEN')
13
- @uri = URI.parse("https://firebaseremoteconfig.googleapis.com/v1/projects/#{@project_id}/remoteConfig")
14
- @source_filepath = @opts[:source]
15
- @etag = File.exist?(@opts[:etag]) ? File.open(@opts[:etag]).read : @opts[:etag] if @opts[:etag]
16
- @ignore_etag = @opts[:force]
17
- @dest_dir = File.join(@opts[:dest], @project_id) if @opts[:dest]
18
-
9
+ @config = Remocon::Config.new(opts)
19
10
  @cmd_opts = { validate_only: false }
20
11
  end
21
12
 
@@ -36,23 +27,27 @@ module Remocon
36
27
  def request
37
28
  return @request if @request
38
29
 
39
- raise 'etag should be specified. If you want to ignore this error, then add --force option' unless @etag || @ignore_etag
30
+ raise "etag should be specified. If you want to ignore this error, then add --force option" unless config.etag
40
31
 
41
32
  headers = {
42
- 'Authorization' => "Bearer #{@token}",
43
- 'Content-Type' => 'application/json; UTF8'
33
+ "Authorization" => "Bearer #{config.token}",
34
+ "Content-Type" => "application/json; UTF8",
35
+ "If-Match" => config.etag,
44
36
  }
45
- headers['If-Match'] = @etag || '*'
46
37
 
47
38
  request = Net::HTTP::Put.new(uri.request_uri, headers)
48
39
  request.body = ""
49
- request.body << File.read(@source_filepath).delete("\r\n")
40
+ request.body << File.read(config.config_json_file_path).delete("\r\n")
50
41
 
51
42
  @request = request
52
43
  end
53
44
 
54
45
  private
55
46
 
47
+ def uri
48
+ @uri ||= URI.parse(config.endpoint)
49
+ end
50
+
56
51
  def do_request
57
52
  response = client.request(request)
58
53
 
@@ -65,28 +60,32 @@ module Remocon
65
60
  when Net::HTTPOK
66
61
  parse_success_body(response, response_body)
67
62
  # intentional behavior
68
- STDERR.puts 'Updated successfully.'
63
+ STDERR.puts "Updated successfully."
69
64
  when Net::HTTPBadRequest
70
65
  # sent json contains errors
71
66
  parse_error_body(response, response_body) if response_body
72
- STDERR.puts '400 but no error body' unless response_body
67
+ STDERR.puts "400 but no error body" unless response_body
73
68
  when Net::HTTPUnauthorized
74
69
  # token was expired
75
- STDERR.puts '401 Unauthorized. A token might be expired or invalid.'
70
+ STDERR.puts "401 Unauthorized. A token might be expired or invalid."
76
71
  when Net::HTTPForbidden
77
72
  # remote config api might be disabled or not yet activated
78
- STDERR.puts '403 Forbidden. RemoteConfig API might not be activated or be disabled.'
73
+ STDERR.puts "403 Forbidden. RemoteConfig API might not be activated or be disabled."
79
74
  when Net::HTTPConflict
80
75
  # local content is out-to-date
81
- STDERR.puts '409 Conflict. Remote was updated. Please update your local files'
76
+ STDERR.puts "409 Conflict. Remote was updated. Please update your local files"
82
77
  end
78
+
79
+ response.kind_of?(Net::HTTPOK)
83
80
  end
84
81
 
85
82
  def parse_success_body(response, _success_body)
86
- return unless etag = response.header["etag"]
83
+ etag = response.header["etag"]
84
+
85
+ return unless etag
87
86
 
88
- if @dest_dir
89
- File.open(File.join(@dest_dir, 'etag'), 'w+') do |f|
87
+ if config.project_dir_path
88
+ File.open(config.etag_file_path, "w+") do |f|
90
89
  f.write(etag)
91
90
  f.flush
92
91
  end
@@ -101,13 +100,13 @@ module Remocon
101
100
 
102
101
  error_body.dig(:error, :details)&.each do |k|
103
102
  # for now, see only errors below
104
- next unless k['@type'] == 'type.googleapis.com/google.rpc.BadRequest'
103
+ next unless k["@type"] == "type.googleapis.com/google.rpc.BadRequest"
105
104
 
106
105
  k[:fieldViolations].each do |e|
107
- if e[:field].start_with?('remote_config.conditions')
108
- STDERR.puts 'CONDITION DEFINITION ERROR'
106
+ if e[:field].start_with?("remote_config.conditions")
107
+ STDERR.puts "CONDITION DEFINITION ERROR"
109
108
  else
110
- STDERR.puts 'PARAMETER DEFINITION ERROR'
109
+ STDERR.puts "PARAMETER DEFINITION ERROR"
111
110
  end
112
111
 
113
112
  STDERR.puts e[:description]
@@ -5,33 +5,43 @@ module Remocon
5
5
  class Validate
6
6
  include Remocon::InterpreterHelper
7
7
 
8
+ attr_reader :config, :cmd_opts
9
+
8
10
  def initialize(opts)
9
- @opts = opts
11
+ @config = Remocon::Config.new(opts)
12
+ @cmd_opts = { validate_only: true }
13
+ end
10
14
 
11
- @conditions_filepath = @opts[:conditions]
12
- @parameters_filepath = @opts[:parameters]
15
+ def require_parameters_file_path
16
+ config.parameters_file_path
17
+ end
13
18
 
14
- @cmd_opts = { validate_only: true }
19
+ def require_conditions_file_path
20
+ config.conditions_file_path
15
21
  end
16
22
 
17
23
  def run
18
24
  validate_options
19
25
 
20
- if parameter_errors.empty? && condition_errors.empty?
21
- STDOUT.puts 'No error was found.'
26
+ errors = parameter_errors + condition_errors
27
+
28
+ if errors.empty?
29
+ STDOUT.puts "No error was found."
22
30
  else
23
- (parameter_errors + condition_errors).each do |e|
31
+ errors.each do |e|
24
32
  STDERR.puts "#{e.class} #{e.message}"
25
33
  STDERR.puts e.backtrace.join("\n")
26
34
  end
27
35
  end
36
+
37
+ errors.empty?
28
38
  end
29
39
 
30
40
  private
31
41
 
32
42
  def validate_options
33
- raise ValidationError, 'A condition file must exist' unless File.exist?(@conditions_filepath)
34
- raise ValidationError, 'A parameter file must exist' unless File.exist?(@parameters_filepath)
43
+ raise ValidationError, "A condition file must exist" unless File.exist?(config.conditions_file_path)
44
+ raise ValidationError, "A parameter file must exist" unless File.exist?(config.parameters_file_path)
35
45
  end
36
46
  end
37
47
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Remocon
4
4
  class ConditionFileInterpreter
5
- SUPPORTED_ATTRIBUTED = %i[name expression tagColor]
5
+ SUPPORTED_ATTRIBUTED = %i(name expression tagColor).freeze
6
6
 
7
7
  def initialize(filepath)
8
8
  # conditions should be Array
@@ -16,14 +16,16 @@ module Remocon
16
16
  keys = []
17
17
 
18
18
  @yaml.each do |hash|
19
- raise Remocon::EmptyNameError, 'name must not be empty' unless hash[:name]
20
- raise Remocon::EmptyExpressionError, 'expression must not be empty' unless hash[:expression]
21
- raise Remocon::DuplicateKeyError, "#{hash[:name]} is duplicated" if keys.include?(hash[:name])
19
+ begin
20
+ raise Remocon::EmptyNameError, "name must not be empty" unless hash[:name]
21
+ raise Remocon::EmptyExpressionError, "expression must not be empty" unless hash[:expression]
22
+ raise Remocon::DuplicateKeyError, "#{hash[:name]} is duplicated" if keys.include?(hash[:name])
22
23
 
23
- keys.push(hash[:name])
24
- rescue Remocon::ValidationError => e
25
- raise e unless opts[:validate_only]
26
- errors.push(e)
24
+ keys.push(hash[:name])
25
+ rescue Remocon::ValidationError => e
26
+ raise e unless opts[:validate_only]
27
+ errors.push(e)
28
+ end
27
29
  end
28
30
 
29
31
  [json_array, errors]
@@ -9,19 +9,21 @@ module Remocon
9
9
  def read(condition_names, opts = {})
10
10
  errors = []
11
11
  json_hash = @yaml.each_with_object({}) do |(key, body), hash|
12
- raise Remocon::DuplicateKeyError, "#{key} is duplicated" if hash[key]
12
+ begin
13
+ raise Remocon::DuplicateKeyError, "#{key} is duplicated" if hash[key]
13
14
 
14
- hash[key] = {
15
- defaultValue: {
16
- value: parse_value_body(key, body)
15
+ hash[key] = {
16
+ defaultValue: {
17
+ value: parse_value_body(key, body)
18
+ }
17
19
  }
18
- }
19
20
 
20
- hash[key][:conditionalValues] = parse_condition_body(condition_names, key, body[:conditions]) if body[:conditions]
21
- hash[key][:description] = body[:description] if body[:description]
22
- rescue Remocon::ValidationError => e
23
- raise e unless opts[:validate_only]
24
- errors.push(e)
21
+ hash[key][:conditionalValues] = parse_condition_body(condition_names, key, body[:conditions]) if body[:conditions]
22
+ hash[key][:description] = body[:description] if body[:description]
23
+ rescue Remocon::ValidationError => e
24
+ raise e unless opts[:validate_only]
25
+ errors.push(e)
26
+ end
25
27
  end
26
28
 
27
29
  [json_hash.with_indifferent_access, errors]
@@ -7,7 +7,8 @@ module Remocon
7
7
  end
8
8
 
9
9
  def validate
10
- str_content = @content.is_a?(Hash) ? @content.to_json : @content.to_s
10
+ str_content = @content.kind_of?(Hash) ? @content.to_json : @content.to_s
11
+ puts str_content
11
12
  @json = JSON.parse(str_content).to_json
12
13
  rescue JSON::ParserError => e
13
14
  raise ValidationError, e.message
@@ -27,7 +27,7 @@ module Remocon
27
27
  end
28
28
 
29
29
  def self.respond_symbol
30
- raise Remocon::UnsupportedTypeError, 'unknown'
30
+ raise Remocon::UnsupportedTypeError, "unknown"
31
31
  end
32
32
  end
33
33
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Remocon
4
4
  module ConditionSorter
5
- CONDITION_KEYS = %i[name expression tagColor]
5
+ CONDITION_KEYS = %i(name expression tagColor).freeze
6
6
 
7
7
  def sort_conditions(conditions)
8
8
  conditions
@@ -12,7 +12,7 @@ module Remocon
12
12
  if !CONDITION_KEYS.include?(a) && !CONDITION_KEYS.include?(b)
13
13
  a <=> b
14
14
  else
15
- (CONDITION_KEYS.index(a) || 10000) <=> (CONDITION_KEYS.index(b) || 10000)
15
+ (CONDITION_KEYS.index(a) || 10_000) <=> (CONDITION_KEYS.index(b) || 10_000)
16
16
  end
17
17
  end
18
18
 
@@ -2,14 +2,14 @@
2
2
 
3
3
  module Remocon
4
4
  module ParameterSorter
5
- PARAMETER_KEYS = %i[description value file normalizer conditions options]
5
+ PARAMETER_KEYS = %i(description value file normalizer conditions options).freeze
6
6
 
7
7
  def sort_parameters(parameters)
8
8
  arr = parameters.sort.map do |k, v|
9
9
  hash_arr = v.sort { |(a, _), (b, _)| PARAMETER_KEYS.index(a) <=> PARAMETER_KEYS.index(b) }
10
- .map do |k, v|
10
+ .map do |k1, v1|
11
11
  {
12
- k => k.to_sym == :conditions ? sort_parameters(v) : v
12
+ k1 => k1.to_sym == :conditions ? sort_parameters(v1) : v1
13
13
  }
14
14
  end
15
15
 
@@ -3,9 +3,9 @@
3
3
  class Array
4
4
  def stringify_values
5
5
  map do |e|
6
- if e.is_a?(Hash)
6
+ if e.kind_of?(Hash)
7
7
  e.stringify_values
8
- elsif e.is_a?(Array)
8
+ elsif e.kind_of?(Array)
9
9
  e.stringify_values
10
10
  else
11
11
  e.to_s
@@ -17,9 +17,9 @@ class Hash
17
17
 
18
18
  def stringify_values
19
19
  self.deep_merge(self) do |_, _, v|
20
- if v.is_a?(Hash)
20
+ if v.kind_of?(Hash)
21
21
  v.stringify_values
22
- elsif v.is_a?(Array)
22
+ elsif v.kind_of?(Array)
23
23
  v.stringify_values
24
24
  else
25
25
  v.to_s
@@ -8,6 +8,6 @@ class String
8
8
  def to_boolean
9
9
  return true if self == "true"
10
10
  return false if self == "false"
11
- raise ArgumentError, 'String cannot be converted to Boolean'
11
+ raise ArgumentError, "String cannot be converted to Boolean"
12
12
  end
13
13
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Remocon
4
- VERSION = '0.1.0'
4
+ VERSION = "0.2.0"
5
5
  end
@@ -0,0 +1,34 @@
1
+ {
2
+ "conditions": [
3
+ {
4
+ "expression": "device.os == 'ios'",
5
+ "name": "condition1",
6
+ "tagColor": "INDIGO"
7
+ },
8
+ {
9
+ "expression": "device.os == 'ios'",
10
+ "name": "zxczx",
11
+ "tagColor": "CYAN"
12
+ }
13
+ ],
14
+ "parameters": {
15
+ "key1": {
16
+ "defaultValue": {
17
+ "value": "100"
18
+ },
19
+ "conditionalValues": {
20
+ "condition1": {
21
+ "value": "200"
22
+ },
23
+ "zxczx": {
24
+ "value": "100"
25
+ }
26
+ }
27
+ },
28
+ "key2": {
29
+ "defaultValue": {
30
+ "value": "123"
31
+ }
32
+ }
33
+ }
34
+ }
@@ -1,42 +1,41 @@
1
-
2
1
  # frozen_string_literal: true
3
2
 
4
- lib = File.expand_path('lib', __dir__)
3
+ lib = File.expand_path("lib", __dir__)
5
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
- require 'remocon/version'
5
+ require "remocon/version"
7
6
 
8
7
  Gem::Specification.new do |spec|
9
- spec.name = 'remocon'
8
+ spec.name = "remocon"
10
9
  spec.version = Remocon::VERSION
11
- spec.authors = ['Jumpei Matsuda']
12
- spec.email = ['jmatsu.drm@gmail.com']
10
+ spec.authors = ["Jumpei Matsuda"]
11
+ spec.email = ["jmatsu.drm@gmail.com"]
13
12
 
14
- spec.summary = 'YAML-based firebase remote config manager'
13
+ spec.summary = "YAML-based firebase remote config manager"
15
14
  spec.description = "This gem manages RemoteConfig's key-values based on YAML configuration."
16
- spec.homepage = 'https://github.com/jmatsu/remocon'
17
- spec.license = 'MIT'
15
+ spec.homepage = "https://github.com/jmatsu/remocon"
16
+ spec.license = "MIT"
18
17
 
19
18
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
20
19
  # to allow pushing to a single host or delete this section to allow pushing to any host.
21
20
  if spec.respond_to?(:metadata)
22
- spec.metadata['allowed_push_host'] = "https://rubygems.org"
21
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
23
22
  else
24
- raise 'RubyGems 2.0 or newer is required to protect against ' \
25
- 'public gem pushes.'
23
+ raise "RubyGems 2.0 or newer is required to protect against " \
24
+ "public gem pushes."
26
25
  end
27
26
 
28
27
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
29
28
  f.match(%r{^(test|spec|features)/})
30
29
  end
31
- spec.bindir = 'cmd'
30
+ spec.bindir = "cmd"
32
31
  spec.executables = spec.files.grep(%r{^cmd/}) { |f| File.basename(f) }
33
- spec.require_paths = ['lib']
32
+ spec.require_paths = ["lib"]
34
33
 
35
- spec.add_dependency 'thor'
36
- spec.add_dependency 'activesupport'
37
- spec.add_development_dependency 'bundler', '~> 1.16'
38
- spec.add_development_dependency 'rake', '~> 10.0'
39
- spec.add_development_dependency 'rspec', '~> 3.0'
40
- spec.add_development_dependency 'pry'
41
- spec.add_development_dependency 'rubocop'
34
+ spec.add_dependency "activesupport"
35
+ spec.add_dependency "thor"
36
+ spec.add_development_dependency "bundler", "~> 1.16"
37
+ spec.add_development_dependency "pry"
38
+ spec.add_development_dependency "rake", "~> 10.0"
39
+ spec.add_development_dependency "rspec", "~> 3.0"
40
+ spec.add_development_dependency "rubocop"
42
41
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remocon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jumpei Matsuda
8
8
  autorequire:
9
9
  bindir: cmd
10
10
  cert_chain: []
11
- date: 2018-03-18 00:00:00.000000000 Z
11
+ date: 2018-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: thor
14
+ name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: activesupport
28
+ name: thor
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -53,47 +53,47 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.16'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rake
56
+ name: pry
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '10.0'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '10.0'
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rspec
70
+ name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '3.0'
75
+ version: '10.0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '3.0'
82
+ version: '10.0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: pry
84
+ name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '3.0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: '3.0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -136,6 +136,7 @@ files:
136
136
  - lib/remocon.rb
137
137
  - lib/remocon/cli.rb
138
138
  - lib/remocon/command/create_command.rb
139
+ - lib/remocon/command/lib/config.rb
139
140
  - lib/remocon/command/lib/interpreter_helper.rb
140
141
  - lib/remocon/command/pull_command.rb
141
142
  - lib/remocon/command/push_command.rb
@@ -160,6 +161,7 @@ files:
160
161
  - lib/remocon/util/hash.rb
161
162
  - lib/remocon/util/string.rb
162
163
  - lib/remocon/version.rb
164
+ - prj/config.json
163
165
  - remocon.gemspec
164
166
  - sample/basketball-b8548/conditions.yml
165
167
  - sample/basketball-b8548/config.json
@@ -186,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
188
  version: '0'
187
189
  requirements: []
188
190
  rubyforge_project:
189
- rubygems_version: 2.7.3
191
+ rubygems_version: 2.5.2.3
190
192
  signing_key:
191
193
  specification_version: 4
192
194
  summary: YAML-based firebase remote config manager