eco-helpers 3.0.14 → 3.0.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -2
  3. data/eco-helpers.gemspec +15 -14
  4. data/lib/eco/api/common/people/default_parsers/date_parser.rb +6 -0
  5. data/lib/eco/api/common/session/mailer/aws_provider.rb +85 -0
  6. data/lib/eco/api/common/session/mailer/provider_base.rb +61 -0
  7. data/lib/eco/api/common/session/mailer/sendgrid_provider.rb +117 -0
  8. data/lib/eco/api/common/session/mailer.rb +42 -71
  9. data/lib/eco/api/session/batch/errors.rb +2 -2
  10. data/lib/eco/api/session/batch.rb +66 -28
  11. data/lib/eco/api/session/config/api.rb +96 -37
  12. data/lib/eco/api/session/config/apis/enviro_spaces.rb +106 -0
  13. data/lib/eco/api/session/config/apis/one_off.rb +94 -0
  14. data/lib/eco/api/session/config/apis/service_up.rb +37 -0
  15. data/lib/eco/api/session/config/apis/space_helpers.rb +41 -0
  16. data/lib/eco/api/session/config/apis.rb +81 -132
  17. data/lib/eco/api/session/config.rb +21 -3
  18. data/lib/eco/api/usecases/default_cases/samples/sftp_case.rb +1 -1
  19. data/lib/eco/api/usecases/graphql/helpers/base/error_handling.rb +19 -8
  20. data/lib/eco/api/usecases/graphql/helpers/base/graphql_env.rb +1 -0
  21. data/lib/eco/api/usecases/graphql/samples/location/command/dsl.rb +3 -7
  22. data/lib/eco/api/usecases/graphql/samples/location/command/service/tree_update.rb +6 -2
  23. data/lib/eco/cli/config/options_set.rb +10 -7
  24. data/lib/eco/cli/scripting/args_helpers.rb +18 -9
  25. data/lib/eco/cli_default/options.rb +8 -0
  26. data/lib/eco/cli_default/people.rb +3 -3
  27. data/lib/eco/language/basic_logger.rb +4 -2
  28. data/lib/eco/version.rb +1 -1
  29. metadata +37 -16
@@ -3,182 +3,131 @@ module Eco
3
3
  class Session
4
4
  class Config
5
5
  class Apis < BaseConfig
6
- def apis
7
- self["apis"] ||= {}
8
- end
9
-
10
- def apis?
11
- apis.keys.length > 0
12
- end
13
-
14
- def enviros
15
- apis.keys
16
- end
6
+ class UndefinedApi < ArgumentError; end
7
+
8
+ require_relative 'apis/space_helpers'
9
+ require_relative 'apis/enviro_spaces'
10
+ require_relative 'apis/one_off'
11
+ require_relative 'apis/service_up'
12
+
13
+ include EnviroSpaces
14
+ include OneOff
15
+ include ServiceUp
16
+
17
+ def add(
18
+ name,
19
+ key:,
20
+ host:,
21
+ space: nil,
22
+ version: :internal,
23
+ mode: :local,
24
+ user_key: nil,
25
+ external_key: nil,
26
+ email: nil,
27
+ pass: nil,
28
+ org_id: nil
29
+ )
30
+ # ensure that space_option isn't used
31
+ space = to_space(space)
32
+
33
+ msg = "WARNING: Overriding #{full_name(name, space: space)} API credentials"
34
+ puts msg if self.defined?(name, space: space)
35
+
36
+ apis(space)[name] = Session::Config::Api.new(
37
+ name,
38
+ space: space,
39
+ key: key,
40
+ host: host,
41
+ version: version,
42
+ mode: mode,
43
+ root: self,
44
+ user_key: user_key,
45
+ external_key: external_key,
46
+ email: email,
47
+ pass: pass,
48
+ org_id: org_id
49
+ )
17
50
 
18
- def defined?(name)
19
- apis.key?(name)
51
+ self
20
52
  end
21
53
 
22
- def any_defined?(*names)
23
- [names].flatten.any? do |name|
24
- self.defined?(name)
25
- end
54
+ # the active environment
55
+ def active_root_name
56
+ active_name
26
57
  end
27
58
 
28
- def add(name, key:, host:, version: :internal,
29
- mode: :local, user_key: nil, external_key: nil,
30
- email: nil, pass: nil, org_id: nil)
31
- apis[name] = Session::Config::Api.new(
32
- name,
33
- key: key,
34
- host: host,
35
- version: version,
36
- mode: mode,
37
- root: self,
38
- user_key: user_key,
39
- external_key: external_key,
40
- email: email,
41
- pass: pass,
42
- org_id: org_id
43
- )
44
- self
59
+ def active_name
60
+ self['active-name']
45
61
  end
46
62
 
47
63
  def active_api
48
- self["active-api"]
64
+ self['active-api']
49
65
  end
50
66
 
51
67
  def active_name=(name)
52
- raise "'#{name}' Api environment not defined" if !apis[name]
53
- self["active-name"] = name
54
- self["active-api"] = apis[name]
55
- self
68
+ set_active_name(name)
56
69
  end
57
70
 
58
- def active_name
59
- self["active-name"]
60
- end
71
+ def set_active_name(name, space: space_option)
72
+ space ||= space_option
61
73
 
62
- # the active environment
63
- def active_root_name
64
- active_name
65
- end
74
+ msg = missing_api_message(name, space: space)
75
+ raise UndefinedApi, msg unless self.api?(name, space: space)
66
76
 
67
- def service_up?
68
- @api_test ||= Session::Config::Api.api_class(active_api.version).new("foobar", host: active_api.host, logger: ::Logger.new(IO::NULL))
69
- status = @api_test.client.get("/policy_groups").status
70
- # 401 Unauthorized "Permission denied. API key may be invalid."
71
- status == 401
77
+ self['active-name'] = name
78
+ self['active-api'] = apis(space)[name]
79
+ set_options_space!(active_space)
80
+
81
+ self
72
82
  end
73
83
 
74
84
  def api(logger = ::Logger.new(IO::NULL), version: nil)
75
- unless active_api
76
- raise "There's no 'active_api'. Use apis.active_name='api_enviro_name' to set the active api"
77
- end
85
+ msg = "There's no 'active_api'. "
86
+ msg << "To set the target environment, please use either of:\n"
87
+ msg << " * apis.set_active_name('api_enviro_name', space: 'the-space')\n"
88
+ msg << " * apis.active_name='api_enviro_name'\n"
89
+ raise msg unless active_api
90
+
78
91
  active_api.api(version: version, logger: logger)
79
92
  end
80
93
 
81
94
  def default_user_key=(key)
82
- self["user_key"] = key
95
+ self['user_key'] = key
83
96
  end
84
97
 
85
98
  def default_user_key
86
- self["user_key"]
99
+ self['user_key']
87
100
  end
88
101
 
89
102
  def default_email=(email)
90
- self["default_email"] = email
103
+ self['default_email'] = email
91
104
  end
92
105
 
93
106
  def default_email
94
- self["default_email"] || ENV['USER_EMAIL']
107
+ self['default_email'] || ENV['USER_EMAIL']
95
108
  end
96
109
 
97
110
  def default_pass=(pass)
98
- self["default_pass"] = pass
111
+ self['default_pass'] = pass
99
112
  end
100
113
 
101
114
  def default_pass
102
- self["default_pass"] || ENV['USER_PASS']
115
+ self['default_pass'] || ENV['USER_PASS']
103
116
  end
104
117
 
105
118
  # Method to support CLI one-off API requests
106
119
  def one_off
107
- if one_off?
108
- add(one_off_org, key: one_off_key, host: "#{one_off_enviro}.ecoportal.com")
109
- return one_off_org
110
- end
111
- end
112
-
113
- private
114
-
115
- def one_off?
116
- @is_one_off ||= SCR.get_arg("-api-key") || SCR.get_arg("-one-off")
117
- end
120
+ return unless one_off?
118
121
 
119
- def one_off_key
120
- return @one_off_key if instance_variable_defined?(:@one_off_key)
121
- if one_off?
122
- Dotenv.load("./.env_one_off")
123
- SCR.get_arg("-api-key", with_param: true).yield_self do |key|
124
- one_off_key_env(key)
125
- end
126
- end
127
- end
128
-
129
- def one_off_key_env(key)
130
- if one_off?
131
- if key
132
- env_file_set_var("./.env_one_off", one_off_key_env_var, key)
133
- key
134
- else
135
- Dotenv.load("./.env_one_off")
136
- ENV[one_off_key_env_var].tap do |k|
137
- raise "At least the first time, you should provide the -api-key" unless k
138
- end
139
- end
140
- end
141
- end
142
-
143
- def one_off_key_env_var
144
- @one_off_key_env_var ||= "#{one_off_org}_KEY"
145
- end
122
+ name = one_off_org
146
123
 
147
- def one_off_org
148
- return @one_off_org if instance_variable_defined?(:@one_off_org)
149
- unless org = SCR.get_arg("-org", with_param: true)
150
- raise("You should specify -org NAME when using -api-key or -one-off")
151
- end
152
- @one_off_org ||= "#{org.downcase.split(/[^a-z]+/).join("_")}_#{one_off_enviro.gsub(".", "_")}".to_sym
153
- end
154
-
155
- def one_off_enviro
156
- return @one_off_enviro if instance_variable_defined?(:@one_off_enviro)
157
- enviro = SCR.get_arg("-enviro") ? SCR.get_arg("-enviro", with_param: true) : "live"
158
- @one_off_enviro ||= enviro.downcase
159
- end
124
+ add(
125
+ name,
126
+ key: one_off_key,
127
+ host: "#{one_off_enviro}.ecoportal.com"
128
+ )
160
129
 
161
- def env_file_set_var(file, var, value)
162
- begin
163
- pattern = /"#{var}=(?<value>[^ \r\n]+)"/
164
- File.open(file, "w+") do |fd|
165
- found = false
166
- fd.each_line do |line|
167
- if match = line.match(pattern)
168
- found = true
169
- # IO::SEEK_CUR => Seeks to _amount_ plus current position
170
- fd.seek(-(line.length + 1), IO::SEEK_CUR)
171
- fd.write line.gsub(match[:value], value)
172
- end
173
- end
174
-
175
- fd << "#{var}=#{value}" unless found
176
- end
177
- rescue StandardError => e
178
- puts "#{e}"
179
- return false
180
- end
181
- return true
130
+ name
182
131
  end
183
132
  end
184
133
  end
@@ -97,18 +97,31 @@ module Eco
97
97
  apis.apis?
98
98
  end
99
99
 
100
+ ApiDefChain = Struct.new(:root, :name, :params) do
101
+ def add_space(space, **kargs, &block)
102
+ kargs = (params || {}).merge(kargs).merge(space: space)
103
+ root.add_api(name, **kargs, &block)
104
+ end
105
+ end
106
+
100
107
  # @param (see Eco::API::Session::Config::Apis#add)
101
108
  # @return [Eco::API::Session::Config] this configuration
102
109
  def add_api(name, **kargs)
103
110
  apis.add(name, **kargs)
104
- self
111
+
112
+ if block_given?
113
+ params = kargs.merge({space: :sub_other})
114
+ yield(ApiDefChain.new(self, name, params))
115
+ end
116
+
117
+ ApiDefChain.new(self, name, {space: :other})
105
118
  end
106
119
 
107
120
  # Set the active api by `name`
108
121
  # @see Eco::API::Session::Config::Apis#active_api=
109
122
  # @return [Eco::API::Session::Config] this configuration
110
- def active_api(name)
111
- apis.active_name = name
123
+ def active_api(name, space: nil)
124
+ apis.set_active_name(name, space: space)
112
125
  self
113
126
  end
114
127
 
@@ -117,6 +130,11 @@ module Eco
117
130
  apis.active_root_name
118
131
  end
119
132
 
133
+ # @see Eco::API::Session::Config::Apis#active_space
134
+ def active_enviro_space
135
+ apis.active_space
136
+ end
137
+
120
138
  # @see Eco::API::Session::Config::Apis#api
121
139
  # @return [Eco::API::Session::Config::Api] the currently active api
122
140
  def api(logger = ::Logger.new(IO::NULL), version: nil)
@@ -71,7 +71,7 @@ class Eco::API::UseCases::DefaultCases::Samples::Sftp < Eco::API::Common::Loader
71
71
  end
72
72
 
73
73
  def to_remote_path(file)
74
- File.join(remote_folder, file)
74
+ [remote_folder, file].compact.join('/')
75
75
  end
76
76
 
77
77
  def local_folder
@@ -3,7 +3,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Base
3
3
  module ErrorHandling
4
4
  include Eco::Language::AuxiliarLogger
5
5
 
6
- attr_reader :exception
6
+ attr_reader :exception, :exiting
7
7
 
8
8
  private
9
9
 
@@ -19,6 +19,14 @@ module Eco::API::UseCases::GraphQL::Helpers::Base
19
19
  exception && !interrupted?
20
20
  end
21
21
 
22
+ def exiting?
23
+ @exiting
24
+ end
25
+
26
+ def exception?
27
+ error_raised? || exiting?
28
+ end
29
+
22
30
  def rescued
23
31
  yield
24
32
  rescue StandardError => err
@@ -27,24 +35,27 @@ module Eco::API::UseCases::GraphQL::Helpers::Base
27
35
  unless exception_already_captured?(err)
28
36
  log(:error) { err.patch_full_message }
29
37
  end
38
+ rescue SystemExit
39
+ @exiting = true
40
+ raise
30
41
  end
31
42
 
32
43
  def with_error_handling
33
44
  @exception = nil
34
45
  yield
35
- rescue SystemExit => sext
36
- @exception = sext
37
- exit sext.status
38
- rescue *interrupt_errors => int
46
+ rescue StandardError, SignalException => err
47
+ @exception = err
48
+ raise
49
+ rescue SystemExit
50
+ @exiting = true
51
+ raise
52
+ rescue *interrupt_errors
39
53
  @exception = int
40
54
  raise
41
55
  rescue SystemStackError
42
56
  puts $! # rubocop:disable Style/SpecialGlobalVars
43
57
  puts caller[0..100]
44
58
  raise
45
- rescue StandardError, SignalException => err
46
- @exception = err
47
- raise
48
59
  end
49
60
 
50
61
  def interrupt_errors
@@ -8,6 +8,7 @@ module Eco::API::UseCases::GraphQL::Helpers::Base
8
8
  def graphql
9
9
  msg = "The credentials or basic graphql config are missing for the active environment"
10
10
  raise msg unless session.api?(version: :graphql)
11
+
11
12
  @graphql ||= session.api(version: :graphql)
12
13
  end
13
14
  end
@@ -49,15 +49,11 @@ class Eco::API::UseCases::GraphQL::Samples::Location
49
49
  end
50
50
 
51
51
  break if error
52
+ rescue StandardError => err
53
+ log(:error) { err.patch_full_message }
54
+ raise
52
55
  end
53
56
  end
54
- rescue SystemStackError
55
- puts $! # rubocop:disable Style/SpecialGlobalVars
56
- puts caller[0..100]
57
- raise
58
- rescue StandardError => err
59
- log(:error) { err.patch_full_message }
60
- raise
61
57
  ensure
62
58
  rescued { self.tags_remap_csv_file = generate_tags_remap_csv }
63
59
  rescued { close_handling_tags_remap_csv }
@@ -21,7 +21,7 @@ class Eco::API::UseCases::GraphQL::Samples::Location
21
21
  super
22
22
  end
23
23
  ensure
24
- rescued { re_archive } unless error_raised?
24
+ rescued { re_archive } unless exception?
25
25
  rescued { email_digest('TagTree Update') }
26
26
  end
27
27
 
@@ -30,7 +30,7 @@ class Eco::API::UseCases::GraphQL::Samples::Location
30
30
  # @note this is an additional necessary step
31
31
  def re_archive
32
32
  return if simulate?
33
- return if error_raised?
33
+ return if exception?
34
34
 
35
35
  stage = :rearchive
36
36
 
@@ -90,8 +90,12 @@ class Eco::API::UseCases::GraphQL::Samples::Location
90
90
 
91
91
  digest_msgs = logger.cache.logs(level: %i[info error warn])
92
92
  str_exception = exception ? " - Exception!" : ''
93
+ str_exception = " - Aborted!" if exiting?
94
+
93
95
  subject = "#{config.active_enviro} - #{title}#{str_exception}"
94
96
 
97
+ digest_msgs << "\n#{exception.patch_full_message(trace_count: 3)}" if exception
98
+
95
99
  session.mail(subject: subject, body: digest_msgs.join).tap do
96
100
  options.deep_merge!({worfklow: {no_email: true}})
97
101
  end
@@ -21,9 +21,11 @@ module Eco
21
21
 
22
22
  ["The following are the available options#{refinement}:"].then do |lines|
23
23
  max_len = keys_max_len(options_args(spaces)) + indent
24
+
24
25
  spaces.each do |namespace|
25
26
  is_general = (namespace == :general)
26
27
  str_indent = is_general ? "" : " " * indent
28
+
27
29
  lines << help_line(namespace, "", max_len) unless is_general
28
30
 
29
31
  options_set(namespace).select do |_arg, option| # rubocop:disable Style/HashEachMethods
@@ -32,6 +34,7 @@ module Eco
32
34
  lines << help_line("#{str_indent}#{option.name}", option.description, max_len)
33
35
  end
34
36
  end
37
+
35
38
  lines
36
39
  end.join("\n")
37
40
  end
@@ -63,13 +66,13 @@ module Eco
63
66
  raise "Missing block to define the options builder" unless block_given?
64
67
 
65
68
  opts = [option].flatten.compact
66
- unless opts.empty?
67
- callback = block
68
- opts.each do |opt|
69
- msg = "Overriding CLI option '#{option}' in '#{namespace}' CLI case / namespace"
70
- puts msg if option_exists?(opt, namespace)
71
- options_set(namespace)[opt] = OptConfig.new(opt, namespace, desc, callback)
72
- end
69
+ return self if opts.empty?
70
+
71
+ callback = block
72
+ opts.each do |opt|
73
+ msg = "Overriding CLI option '#{option}' in '#{namespace}' CLI case / namespace"
74
+ puts msg if option_exists?(opt, namespace)
75
+ options_set(namespace)[opt] = OptConfig.new(opt, namespace, desc, callback)
73
76
  end
74
77
 
75
78
  self
@@ -78,15 +78,24 @@ module Eco
78
78
 
79
79
  # @return [String, Boolean] the argument value if `with_param` or a `Boolean` if not.
80
80
  def get_arg(key, with_param: false, valid: true)
81
- # track what a known option looks like
82
- known_argument(key, with_param: with_param)
83
- return nil unless (index = get_arg_index(key))
84
- return true unless with_param
85
-
86
- value = argv[index + 1]
87
- #puts "modifier argument: #{value}"
88
- value = nil if valid && is_modifier?(value)
89
- value
81
+ case key
82
+ when Array
83
+ key.reduce(nil) do |value, k|
84
+ next value unless value.nil?
85
+
86
+ get_arg(k, with_param: with_param, valid: valid)
87
+ end
88
+ else
89
+ # track what a known option looks like
90
+ known_argument(key, with_param: with_param)
91
+ return nil unless (index = get_arg_index(key))
92
+ return true unless with_param
93
+
94
+ value = argv[index + 1]
95
+ #puts "modifier argument: #{value}"
96
+ value = nil if valid && is_modifier?(value)
97
+ value
98
+ end
90
99
  end
91
100
 
92
101
  # @return [String] the filename.
@@ -153,6 +153,14 @@ ASSETS.cli.config do |cnf| # rubocop:disable Metrics/BlockLength
153
153
  session.config.dry_run!
154
154
  end
155
155
 
156
+ desc = "Specifies the target API key space (i.e. uat, dev, etc.). "
157
+ desc << "Use with CAUTION !!!"
158
+ options_set.add('-space', desc) do |options, session|
159
+ next unless space = SCR.get_arg('-space', with_param: true)
160
+
161
+ options.deep_merge!(api: {space: space.to_sym})
162
+ end
163
+
156
164
  desc = "It specifies the type of batch to be used (default: ':batch')"
157
165
  options_set.add("-batch-mode", desc) do |options, session|
158
166
  mode_in = SCR.get_arg("-batch-mode", with_param: true)
@@ -23,7 +23,8 @@ ASSETS.cli.config do |cnf|
23
23
 
24
24
  msg = "(Optimization) "
25
25
  msg << "Switching from partial to full people download. "
26
- msg << "Input (#{input.count}) surpases MAX_GET_PARTIAL (#{MAX_GET_PARTIAL}) entries."
26
+ msg << "Input (#{input.count}) surpases MAX_GET_PARTIAL "
27
+ msg << "(#{MAX_GET_PARTIAL}) entries."
27
28
  session.log(:info) { msg }
28
29
 
29
30
  options.deep_merge!(people: {
@@ -46,8 +47,6 @@ ASSETS.cli.config do |cnf|
46
47
  elsif get_by_file
47
48
  # -people-from-backup
48
49
  session.micro.people_load(get[:file], modifier: :file)
49
- #people = JSON.parse(File.read(get[:file]))
50
- #Eco::API::Organization::People.new(people)
51
50
  else
52
51
  options.deep_merge!(people: {
53
52
  get: {
@@ -67,6 +66,7 @@ ASSETS.cli.config do |cnf|
67
66
  })
68
67
  people = session.micro.people_cache
69
68
  end
69
+
70
70
  people
71
71
  end
72
72
  end
@@ -24,6 +24,7 @@ module Eco
24
24
  def initialize(level: ::Logger::INFO, timestamp: false)
25
25
  @level = level
26
26
  self.timestamp = timestamp
27
+
27
28
  loggers[:console] = ::Logger.new($stdout).tap do |logger|
28
29
  logger.formatter = format_proc(console: true)
29
30
  logger.level = level
@@ -51,13 +52,14 @@ module Eco
51
52
  end
52
53
 
53
54
  def console_timestamp(datetime)
54
- return nil unless timestamp?
55
+ return unless timestamp?
55
56
 
56
57
  timestamp(datetime)
57
58
  end
58
59
 
59
60
  def timestamp(datetime)
60
- return nil unless datetime
61
+ return unless datetime
62
+
61
63
  str_date = datetime.strftime(self.class::TIMESTAMP_PATTERN)
62
64
  "#{str_date} > "
63
65
  end
data/lib/eco/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eco
2
- VERSION = '3.0.14'.freeze
2
+ VERSION = '3.0.15'.freeze
3
3
  end