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