remocon 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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