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.
- checksums.yaml +5 -5
- data/.gitignore +2 -0
- data/.rubocop.yml +133 -25
- data/.ruby-version +1 -1
- data/.travis.yml +9 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +24 -22
- data/README.md +29 -7
- data/Rakefile +15 -2
- data/bin/console +3 -3
- data/bin/get_access_token +2 -0
- data/bin/get_access_token.py +2 -2
- data/cmd/remocon +1 -1
- data/lib/remocon.rb +46 -45
- data/lib/remocon/cli.rb +27 -15
- data/lib/remocon/command/create_command.rb +16 -16
- data/lib/remocon/command/lib/config.rb +82 -0
- data/lib/remocon/command/lib/interpreter_helper.rb +13 -3
- data/lib/remocon/command/pull_command.rb +34 -35
- data/lib/remocon/command/push_command.rb +27 -28
- data/lib/remocon/command/validate_command.rb +19 -9
- data/lib/remocon/interpreter/condition_file_interpreter.rb +10 -8
- data/lib/remocon/interpreter/parameter_file_interpreter.rb +12 -10
- data/lib/remocon/normalizer/json_normalizer.rb +2 -1
- data/lib/remocon/normalizer/normalizer.rb +1 -1
- data/lib/remocon/sorter/condition_sorter.rb +2 -2
- data/lib/remocon/sorter/parameter_sorter.rb +3 -3
- data/lib/remocon/util/array.rb +2 -2
- data/lib/remocon/util/hash.rb +2 -2
- data/lib/remocon/util/string.rb +1 -1
- data/lib/remocon/version.rb +1 -1
- data/prj/config.json +34 -0
- data/remocon.gemspec +20 -21
- metadata +20 -18
data/bin/get_access_token
CHANGED
@@ -3,8 +3,10 @@
|
|
3
3
|
set -eu
|
4
4
|
|
5
5
|
if type easy_install >/dev/null 2>&1; then
|
6
|
+
sudo easy_install --upgrade oauth2client
|
6
7
|
sudo easy_install --upgrade google-api-python-client
|
7
8
|
else
|
9
|
+
sudo pip install --upgrade oauth2client
|
8
10
|
sudo pip install --upgrade google-api-python-client
|
9
11
|
fi
|
10
12
|
|
data/bin/get_access_token.py
CHANGED
@@ -7,7 +7,7 @@ from oauth2client.service_account import ServiceAccountCredentials
|
|
7
7
|
|
8
8
|
def print_access_token():
|
9
9
|
argv = sys.argv
|
10
|
-
|
10
|
+
if (len(argv) < 1):
|
11
11
|
print >> sys.stderr, 'a filepath to service-account.json must be specified as the 1st argument.'
|
12
12
|
quit()
|
13
13
|
credentials = ServiceAccountCredentials.from_json_keyfile_name(
|
@@ -15,4 +15,4 @@ def print_access_token():
|
|
15
15
|
access_token_info = credentials.get_access_token()
|
16
16
|
print(access_token_info.access_token)
|
17
17
|
|
18
|
-
print_access_token
|
18
|
+
print_access_token()
|
data/cmd/remocon
CHANGED
data/lib/remocon.rb
CHANGED
@@ -1,47 +1,48 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
|
17
|
-
require
|
18
|
-
require
|
19
|
-
|
20
|
-
require
|
21
|
-
require
|
22
|
-
|
23
|
-
require
|
24
|
-
require
|
25
|
-
|
26
|
-
require
|
27
|
-
require
|
28
|
-
|
29
|
-
require
|
30
|
-
require
|
31
|
-
|
32
|
-
require
|
33
|
-
require
|
34
|
-
require
|
35
|
-
require
|
36
|
-
require
|
37
|
-
require
|
38
|
-
require
|
39
|
-
|
40
|
-
require
|
41
|
-
|
42
|
-
|
43
|
-
require
|
44
|
-
require
|
45
|
-
require
|
46
|
-
|
47
|
-
|
3
|
+
require "yaml"
|
4
|
+
require "json"
|
5
|
+
require "thor"
|
6
|
+
require "active_support"
|
7
|
+
require "active_support/core_ext"
|
8
|
+
require "singleton"
|
9
|
+
require "open-uri"
|
10
|
+
require "fileutils"
|
11
|
+
require "net/http"
|
12
|
+
|
13
|
+
require "remocon/util/array"
|
14
|
+
require "remocon/util/hash"
|
15
|
+
require "remocon/util/string"
|
16
|
+
|
17
|
+
require "remocon/version"
|
18
|
+
require "remocon/type"
|
19
|
+
|
20
|
+
require "remocon/error/unsupported_type_error"
|
21
|
+
require "remocon/error/validation_error"
|
22
|
+
|
23
|
+
require "remocon/sorter/condition_sorter"
|
24
|
+
require "remocon/sorter/parameter_sorter"
|
25
|
+
|
26
|
+
require "remocon/dumper/condition_file_dumper"
|
27
|
+
require "remocon/dumper/parameter_file_dumper"
|
28
|
+
|
29
|
+
require "remocon/interpreter/condition_file_interpreter"
|
30
|
+
require "remocon/interpreter/parameter_file_interpreter"
|
31
|
+
|
32
|
+
require "remocon/normalizer/normalizer"
|
33
|
+
require "remocon/normalizer/boolean_normalizer"
|
34
|
+
require "remocon/normalizer/integer_normalizer"
|
35
|
+
require "remocon/normalizer/json_normalizer"
|
36
|
+
require "remocon/normalizer/string_normalizer"
|
37
|
+
require "remocon/normalizer/void_normalizer"
|
38
|
+
require "remocon/normalizer/type_normalizer_factory"
|
39
|
+
|
40
|
+
require "remocon/command/lib/config"
|
41
|
+
require "remocon/command/lib/interpreter_helper"
|
42
|
+
|
43
|
+
require "remocon/command/create_command"
|
44
|
+
require "remocon/command/pull_command"
|
45
|
+
require "remocon/command/push_command"
|
46
|
+
require "remocon/command/validate_command"
|
47
|
+
|
48
|
+
require "remocon/cli"
|
data/lib/remocon/cli.rb
CHANGED
@@ -2,32 +2,44 @@
|
|
2
2
|
|
3
3
|
module Remocon
|
4
4
|
class CLI < ::Thor
|
5
|
-
desc
|
6
|
-
option :parameters, type: :string,
|
7
|
-
option :conditions, type: :string,
|
8
|
-
option :
|
5
|
+
desc "create", "Create a json to be pushed"
|
6
|
+
option :parameters, type: :string, desc: "Specify the filepath if you want to use a custom parameters file"
|
7
|
+
option :conditions, type: :string, desc: "Specify the filepath if you want to use a custom conditions file"
|
8
|
+
option :prefix, type: :string, desc: "the directory name which will contain project-related files"
|
9
|
+
option :id, type: :string, desc: "your project"
|
10
|
+
option :dest, type: :string, hide: true, desc: "[Deprecated] the same with --prefix"
|
9
11
|
def create
|
10
12
|
execute(Remocon::Command::Create)
|
11
13
|
end
|
12
14
|
|
13
|
-
desc
|
14
|
-
|
15
|
-
option :etag, type: :string, desc:
|
16
|
-
option :
|
17
|
-
option :
|
15
|
+
desc "push", "Upload remote configs based on a source json file"
|
16
|
+
option :source, type: :string, desc: "the filepath of your config json file"
|
17
|
+
option :etag, type: :string, desc: "the file path of etag"
|
18
|
+
option :raw_etag, type: :string, desc: "the raw value of etag"
|
19
|
+
option :prefix, type: :string, desc: "the directory name which will contain project-related files"
|
20
|
+
option :force, type: :boolean, default: false, desc: "force to ignore some warnings"
|
21
|
+
option :token, type: :string, desc: "access token to your project"
|
22
|
+
option :id, type: :string, desc: "your project id"
|
23
|
+
option :dest, type: :string, hide: true, desc: "[Deprecated] the same with --prefix"
|
18
24
|
def push
|
19
25
|
execute(Remocon::Command::Push)
|
20
26
|
end
|
21
27
|
|
22
|
-
desc
|
23
|
-
option :
|
28
|
+
desc "pull", "Pull remote configs"
|
29
|
+
option :prefix, type: :string, desc: "the directory name which will contain project-related files"
|
30
|
+
option :token, type: :string, desc: "access token to your project"
|
31
|
+
option :id, type: :string, desc: "your project id"
|
32
|
+
option :dest, type: :string, hide: true, desc: "[Deprecated] the same with --prefix"
|
24
33
|
def pull
|
25
34
|
execute(Remocon::Command::Pull)
|
26
35
|
end
|
27
36
|
|
28
|
-
desc
|
29
|
-
option :parameters, type: :string,
|
30
|
-
option :conditions, type: :string,
|
37
|
+
desc "validate", "Validate yml files"
|
38
|
+
option :parameters, type: :string, desc: "Specify the filepath if you want to use a custom parameters file"
|
39
|
+
option :conditions, type: :string, desc: "Specify the filepath if you want to use a custom conditions file"
|
40
|
+
option :prefix, type: :string, desc: "the directory name which will contain project-related files"
|
41
|
+
option :id, type: :string, desc: "your project id"
|
42
|
+
option :token, type: :string, desc: "access token to your project"
|
31
43
|
def validate
|
32
44
|
execute(Remocon::Command::Validate)
|
33
45
|
end
|
@@ -35,7 +47,7 @@ module Remocon
|
|
35
47
|
private
|
36
48
|
|
37
49
|
def execute(klass)
|
38
|
-
klass.new(options).run
|
50
|
+
exit(1) unless klass.new(options).run
|
39
51
|
end
|
40
52
|
end
|
41
53
|
end
|
@@ -5,15 +5,19 @@ module Remocon
|
|
5
5
|
class Create
|
6
6
|
include Remocon::InterpreterHelper
|
7
7
|
|
8
|
+
attr_reader :config, :cmd_opts
|
9
|
+
|
8
10
|
def initialize(opts)
|
9
|
-
@
|
11
|
+
@config = Remocon::Config.new(opts)
|
12
|
+
@cmd_opts = { validate_only: false }
|
13
|
+
end
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
@dest_dir = File.join(@opts[:dest], @project_id) if @opts[:dest]
|
15
|
+
def require_parameters_file_path
|
16
|
+
config.parameters_file_path
|
17
|
+
end
|
15
18
|
|
16
|
-
|
19
|
+
def require_conditions_file_path
|
20
|
+
config.conditions_file_path
|
17
21
|
end
|
18
22
|
|
19
23
|
def run
|
@@ -24,14 +28,10 @@ module Remocon
|
|
24
28
|
parameters: parameter_hash
|
25
29
|
}.skip_nil_values.stringify_values
|
26
30
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
f.flush
|
32
|
-
end
|
33
|
-
else
|
34
|
-
STDOUT.puts JSON.pretty_generate(artifact)
|
31
|
+
File.open(config.config_json_file_path, "w+") do |f|
|
32
|
+
# remote config allows only string values ;(
|
33
|
+
f.write(JSON.pretty_generate(artifact))
|
34
|
+
f.flush
|
35
35
|
end
|
36
36
|
|
37
37
|
artifact
|
@@ -40,8 +40,8 @@ module Remocon
|
|
40
40
|
private
|
41
41
|
|
42
42
|
def validate_options
|
43
|
-
raise ValidationError,
|
44
|
-
raise ValidationError,
|
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)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Remocon
|
4
|
+
class Config
|
5
|
+
REMOCON_PROJECT_ID_KEY = "REMOCON_FIREBASE_PROJECT_ID"
|
6
|
+
REMOCON_ACCESS_TOKEN = "REMOCON_FIREBASE_ACCESS_TOKEN"
|
7
|
+
|
8
|
+
REMOCON_PREFIX_KEY = "REMOCON_PREFIX"
|
9
|
+
|
10
|
+
CONFIG_JSON_FILE = "config.json"
|
11
|
+
CONDITIONS_FILE_NAME = "conditions.yml"
|
12
|
+
PARAMETERS_FILE_NAME = "parameters.yml"
|
13
|
+
ETAG_FILE_NAME = "etag"
|
14
|
+
|
15
|
+
attr_reader :opts
|
16
|
+
|
17
|
+
def initialize(opts)
|
18
|
+
@opts = opts
|
19
|
+
end
|
20
|
+
|
21
|
+
def endpoint
|
22
|
+
@endpoint ||= "https://firebaseremoteconfig.googleapis.com/v1/projects/#{project_id}/remoteConfig"
|
23
|
+
end
|
24
|
+
|
25
|
+
def project_id
|
26
|
+
# FIREBASE_PROJECT_ID is for backward compatibility
|
27
|
+
@project_id ||= (opts[:id] || ENV[REMOCON_PROJECT_ID_KEY] || ENV["FIREBASE_PROJECT_ID"] || raise("--id or #{REMOCON_PROJECT_ID_KEY} env var is required"))
|
28
|
+
end
|
29
|
+
|
30
|
+
def token
|
31
|
+
# REMOTE_CONFIG_ACCESS_TOKEN is for backward compatibility
|
32
|
+
@token ||= (opts[:token] || ENV[REMOCON_ACCESS_TOKEN] || ENV["REMOTE_CONFIG_ACCESS_TOKEN"] || raise("--token or #{REMOCON_ACCESS_TOKEN} env var is required"))
|
33
|
+
end
|
34
|
+
|
35
|
+
def destination_dir_path
|
36
|
+
@destination_dir_path ||= (opts[:prefix] || opts[:dest] || ENV[REMOCON_PREFIX_KEY])
|
37
|
+
end
|
38
|
+
|
39
|
+
def project_dir_path
|
40
|
+
@project_dir_path ||= begin
|
41
|
+
dir_path = destination_dir_path
|
42
|
+
(dir_path ? File.join(dir_path, project_id) : project_id).tap do |dir|
|
43
|
+
FileUtils.mkdir_p(dir)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def config_json_file_path
|
49
|
+
@config_json_file_path ||= opts[:source] || begin
|
50
|
+
File.join(project_dir_path, CONFIG_JSON_FILE)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def conditions_file_path
|
55
|
+
@conditions_file_path ||= opts[:conditions] || begin
|
56
|
+
File.join(project_dir_path, CONDITIONS_FILE_NAME)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def parameters_file_path
|
61
|
+
@parameters_file_path ||= opts[:parameters] || begin
|
62
|
+
File.join(project_dir_path, PARAMETERS_FILE_NAME)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def etag_file_path
|
67
|
+
@etag_file_path ||= opts[:etag] || begin
|
68
|
+
File.join(project_dir_path, ETAG_FILE_NAME)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def etag
|
73
|
+
@etag ||= begin
|
74
|
+
if opts[:force] && opts[:raw_etag]
|
75
|
+
raise "--force and --raw_etag cannot be specified"
|
76
|
+
end
|
77
|
+
|
78
|
+
opts[:force] && "*" || opts[:raw_etag] || File.exist?(etag_file_path) && File.open(etag_file_path).read
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -5,11 +5,21 @@ module Remocon
|
|
5
5
|
include Remocon::ConditionSorter
|
6
6
|
include Remocon::ParameterSorter
|
7
7
|
|
8
|
-
|
8
|
+
def cmd_opts
|
9
|
+
raise NotImplementedError
|
10
|
+
end
|
11
|
+
|
12
|
+
def require_parameters_file_path
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
def require_conditions_file_path
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
9
19
|
|
10
20
|
def read_parameters
|
11
21
|
@read_parameters ||= begin
|
12
|
-
parameter_interpreter = Remocon::ParameterFileInterpreter.new(
|
22
|
+
parameter_interpreter = Remocon::ParameterFileInterpreter.new(require_parameters_file_path)
|
13
23
|
parameter_interpreter.read(condition_names, cmd_opts)
|
14
24
|
end
|
15
25
|
end
|
@@ -24,7 +34,7 @@ module Remocon
|
|
24
34
|
|
25
35
|
def read_conditions
|
26
36
|
@read_conditions ||= begin
|
27
|
-
condition_interpreter = Remocon::ConditionFileInterpreter.new(
|
37
|
+
condition_interpreter = Remocon::ConditionFileInterpreter.new(require_conditions_file_path)
|
28
38
|
condition_interpreter.read(cmd_opts)
|
29
39
|
end
|
30
40
|
end
|
@@ -5,61 +5,60 @@ module Remocon
|
|
5
5
|
class Pull
|
6
6
|
include Remocon::InterpreterHelper
|
7
7
|
|
8
|
+
attr_reader :config, :cmd_opts
|
9
|
+
|
8
10
|
def initialize(opts)
|
9
|
-
@
|
11
|
+
@config = Remocon::Config.new(opts)
|
12
|
+
@cmd_opts = { validate_only: false }
|
13
|
+
end
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
@dest_dir = File.join(@opts[:dest], @project_id) if @opts[:dest]
|
15
|
+
def require_parameters_file_path
|
16
|
+
config.parameters_file_path
|
17
|
+
end
|
15
18
|
|
16
|
-
|
19
|
+
def require_conditions_file_path
|
20
|
+
config.conditions_file_path
|
17
21
|
end
|
18
22
|
|
19
23
|
def run
|
20
|
-
|
21
|
-
FileUtils.mkdir_p(@dest_dir)
|
24
|
+
raw_json, etag = do_request
|
22
25
|
|
23
|
-
|
26
|
+
raw_hash = JSON.parse(raw_json).with_indifferent_access
|
24
27
|
|
25
|
-
|
28
|
+
raise "etag cannot be fetched. please try again" unless etag
|
26
29
|
|
27
|
-
|
30
|
+
conditions = raw_hash[:conditions] || []
|
31
|
+
parameters = raw_hash[:parameters] || {}
|
28
32
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
+
File.open(config.conditions_file_path, "w+") do |f|
|
34
|
+
f.write(JSON.parse(Remocon::ConditionFileDumper.new(sort_conditions(conditions)).dump.to_json).to_yaml)
|
35
|
+
f.flush
|
36
|
+
end
|
33
37
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
+
File.open(config.parameters_file_path, "w+") do |f|
|
39
|
+
f.write(JSON.parse(Remocon::ParameterFileDumper.new(sort_parameters(parameters)).dump.to_json).to_yaml)
|
40
|
+
f.flush
|
41
|
+
end
|
38
42
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
+
File.open(config.config_json_file_path, "w+") do |f|
|
44
|
+
f.write(JSON.pretty_generate({ conditions: sort_conditions(conditions), parameters: sort_parameters(parameters) }))
|
45
|
+
f.flush
|
46
|
+
end
|
43
47
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
48
|
-
else
|
49
|
-
STDOUT.puts raw_json
|
48
|
+
File.open(config.etag_file_path, "w+") do |f|
|
49
|
+
f.write(etag)
|
50
|
+
f.flush
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
53
54
|
private
|
54
55
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
@raw_json, @etag = open(@url, 'Authorization' => "Bearer #{@token}") do |io|
|
59
|
-
[io.read, io.meta['etag']]
|
56
|
+
def do_request
|
57
|
+
raw_json, etag = open(config.endpoint, "Authorization" => "Bearer #{config.token}") do |io|
|
58
|
+
[io.read, io.meta["etag"]]
|
60
59
|
end
|
61
60
|
|
62
|
-
|
61
|
+
[raw_json, etag]
|
63
62
|
end
|
64
63
|
end
|
65
64
|
end
|