wavefront-cli 0.0.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -1
  3. data/Gemfile +1 -1
  4. data/README.md +21 -21
  5. data/Rakefile +2 -2
  6. data/bin/{wavefront → wf} +6 -2
  7. data/lib/wavefront-cli/alert.rb +7 -6
  8. data/lib/wavefront-cli/base.rb +27 -6
  9. data/lib/wavefront-cli/commands/alert.rb +2 -1
  10. data/lib/wavefront-cli/commands/base.rb +54 -29
  11. data/lib/wavefront-cli/commands/dashboard.rb +1 -0
  12. data/lib/wavefront-cli/commands/event.rb +7 -3
  13. data/lib/wavefront-cli/commands/integration.rb +2 -1
  14. data/lib/wavefront-cli/commands/link.rb +2 -2
  15. data/lib/wavefront-cli/commands/proxy.rb +2 -1
  16. data/lib/wavefront-cli/commands/savedsearch.rb +2 -1
  17. data/lib/wavefront-cli/commands/source.rb +3 -2
  18. data/lib/wavefront-cli/commands/webhook.rb +2 -1
  19. data/lib/wavefront-cli/commands/window.rb +2 -1
  20. data/lib/wavefront-cli/commands/write.rb +10 -6
  21. data/lib/wavefront-cli/constants.rb +1 -1
  22. data/lib/wavefront-cli/controller.rb +6 -4
  23. data/lib/wavefront-cli/dashboard.rb +6 -6
  24. data/lib/wavefront-cli/display/alert.rb +8 -4
  25. data/lib/wavefront-cli/display/base.rb +115 -170
  26. data/lib/wavefront-cli/display/cloudintegration.rb +2 -2
  27. data/lib/wavefront-cli/display/event.rb +1 -1
  28. data/lib/wavefront-cli/display/maintenancewindow.rb +1 -1
  29. data/lib/wavefront-cli/display/metric.rb +6 -7
  30. data/lib/wavefront-cli/display/printer/base.rb +24 -0
  31. data/lib/wavefront-cli/display/printer/long.rb +186 -0
  32. data/lib/wavefront-cli/display/printer/terse.rb +55 -0
  33. data/lib/wavefront-cli/display/query.rb +1 -2
  34. data/lib/wavefront-cli/display/savedsearch.rb +1 -1
  35. data/lib/wavefront-cli/display/source.rb +7 -3
  36. data/lib/wavefront-cli/display/webhook.rb +3 -4
  37. data/lib/wavefront-cli/event.rb +62 -23
  38. data/lib/wavefront-cli/exception.rb +1 -1
  39. data/lib/wavefront-cli/opt_handler.rb +6 -6
  40. data/lib/wavefront-cli/query.rb +5 -6
  41. data/lib/wavefront-cli/source.rb +5 -1
  42. data/lib/wavefront-cli/string.rb +59 -0
  43. data/lib/wavefront-cli/version.rb +1 -1
  44. data/lib/wavefront-cli/write.rb +4 -1
  45. data/spec/spec_helper.rb +1 -1
  46. data/spec/wavefront-cli/alert_spec.rb +16 -5
  47. data/spec/wavefront-cli/base_spec.rb +5 -2
  48. data/spec/wavefront-cli/cli_help_spec.rb +7 -5
  49. data/spec/wavefront-cli/cloudintegration_spec.rb +9 -0
  50. data/spec/wavefront-cli/commands/alert_spec.rb +16 -0
  51. data/spec/wavefront-cli/commands/base_spec.rb +133 -0
  52. data/spec/wavefront-cli/commands/dashboard_spec.rb +16 -0
  53. data/spec/wavefront-cli/commands/event_spec.rb +17 -0
  54. data/spec/wavefront-cli/commands/integration_spec.rb +21 -0
  55. data/spec/wavefront-cli/commands/link_spec.rb +21 -0
  56. data/spec/wavefront-cli/commands/message_spec.rb +16 -0
  57. data/spec/wavefront-cli/commands/metric_spec.rb +16 -0
  58. data/spec/wavefront-cli/commands/proxy_spec.rb +16 -0
  59. data/spec/wavefront-cli/commands/query_spec.rb +16 -0
  60. data/spec/wavefront-cli/commands/spec_helper.rb +4 -0
  61. data/spec/wavefront-cli/commands/webhook_spec.rb +16 -0
  62. data/spec/wavefront-cli/commands/window_spec.rb +21 -0
  63. data/spec/wavefront-cli/commands/write_spec.rb +17 -0
  64. data/spec/wavefront-cli/dashboard_spec.rb +14 -4
  65. data/spec/wavefront-cli/display/base_spec.rb +162 -0
  66. data/spec/wavefront-cli/display/printer/base_spec.rb +20 -0
  67. data/spec/wavefront-cli/display/printer/long_spec.rb +137 -0
  68. data/spec/wavefront-cli/display/printer/terse_spec.rb +46 -0
  69. data/spec/wavefront-cli/display/spec_helper.rb +5 -0
  70. data/spec/wavefront-cli/event_spec.rb +9 -0
  71. data/spec/wavefront-cli/externallink_spec.rb +9 -0
  72. data/spec/wavefront-cli/maintanancewindow_spec.rb +10 -0
  73. data/spec/wavefront-cli/proxy_spec.rb +9 -0
  74. data/spec/wavefront-cli/savedsearch_spec.rb +9 -0
  75. data/spec/wavefront-cli/source_spec.rb +13 -1
  76. data/spec/wavefront-cli/string_spec.rb +51 -0
  77. data/spec/wavefront-cli/user_spec.rb +2 -2
  78. data/spec/wavefront-cli/webhook_spec.rb +9 -0
  79. data/wavefront-cli.gemspec +5 -5
  80. metadata +59 -22
  81. data/Gemfile.lock +0 -65
@@ -0,0 +1,186 @@
1
+ require_relative './base'
2
+ require_relative '../../string'
3
+
4
+ module WavefrontDisplayPrinter
5
+ #
6
+ # Print the long indented descriptions of things
7
+ #
8
+ class Long < Base
9
+ attr_reader :indent, :indent_str, :indent_step, :kw, :hide_blank
10
+
11
+ def initialize(data, fields = nil, modified_data = nil)
12
+ @out = []
13
+ @indent = 0
14
+ @indent_step = 2
15
+ @hide_blank = true
16
+ _two_columns(modified_data || data, nil, fields)
17
+ end
18
+
19
+ # A recursive function which displays a key-value hash in two
20
+ # columns. The key column width is automatically calculated.
21
+ # Multiple-value 'v's are printed one per line. Hashes are nested.
22
+ #
23
+ # @param data [Array] and array of objects to display. Each object
24
+ # should be a hash.
25
+ # @param indent [Integer] how many characters to indent the current
26
+ # data.
27
+ # @kw [Integer] the width of the first (key) column.
28
+ # @returns [Nil]
29
+ #
30
+ def _two_columns(data, kw = nil, fields = nil)
31
+ [data].flatten.each do |item|
32
+ preen_fields(item, fields)
33
+ kw = key_width(item) unless kw
34
+ @kw = kw unless @kw
35
+ mk_indent(indent)
36
+ item.each { |k, v| parse_line(k, v) }
37
+ add_line(nil) if indent.zero?
38
+ end
39
+
40
+ @indent -= indent_step if indent > 0
41
+ @kw += 2
42
+ mk_indent(indent)
43
+ end
44
+
45
+ # Drop any fields not required.
46
+ #
47
+ # @param item [Hash, Map] the raw data
48
+ # @param fields [Array[Symbol]] the fields we wish to keep
49
+ # @return [Hash, Map]
50
+ #
51
+ def preen_fields(item, fields = nil)
52
+ return item unless fields
53
+ item.keep_if { |k, _v| fields.include?(k.to_sym) }
54
+ end
55
+
56
+ # Remove HTML and stuff
57
+ #
58
+ # @param [String] raw value
59
+ # @return [String] value with all HTML stripped out
60
+ #
61
+ def preen_value(value)
62
+ return value unless value.is_a?(String) && value =~ /<.*>/
63
+ value.gsub(%r{<\/?[^>]*>}, '').delete("\n")
64
+ end
65
+
66
+ # Return true if this line is blank and we don't want to print
67
+ # blank lines
68
+ #
69
+ # @param value [Object] thing to check
70
+ # @return [Boolean]
71
+ #
72
+ def blank?(value)
73
+ value.respond_to?(:empty?) && value.empty? && hide_blank
74
+ end
75
+
76
+ # Parse a line and add it to the output or pass it on to another
77
+ # method which knows how to add it to the output.
78
+ #
79
+ # @param key [String] a key
80
+ # @param value [Object] the value: could be anything
81
+ # @return [Nil]
82
+ #
83
+ def parse_line(key, value)
84
+ return if blank?(value)
85
+
86
+ value = preen_value(value)
87
+
88
+ if value.is_a?(Hash)
89
+ add_hash(key, value)
90
+ elsif value.is_a?(Array)
91
+ add_array(key, value)
92
+ else
93
+ add_line(key, value)
94
+ end
95
+ end
96
+
97
+ # Add a key-value pair to the output when value is an array. It
98
+ # will put the key and the first value element on the first
99
+ # line, with subsequent value elements aligned at the same
100
+ # offset, but with no key. If any value element is a hash, it is
101
+ # handled by a separate method. For instance:
102
+ #
103
+ # key value1
104
+ # value2
105
+ # value3
106
+ #
107
+ # @param key [String] the key
108
+ # @param value_arr [Array] an array of values
109
+ # @return [Nil]
110
+ #
111
+ def add_array(key, value_arr)
112
+ value_arr.each_with_index do |element, index|
113
+ if element.is_a?(Hash)
114
+ add_hash(key, element, value_arr.size, index)
115
+ else
116
+ add_line(index.zero? ? key : nil, element)
117
+ end
118
+ end
119
+ end
120
+
121
+ # Add a hash to the output. It will put the key on a line on its
122
+ # own, followed by other keys indented. All values are aligned
123
+ # to the same point. If this hash is a member of an array, we
124
+ # are able to print a horizontal rule at the end of it. We don't
125
+ # do this if it is the final member of the array.
126
+ #
127
+ # For instance:
128
+ #
129
+ # key
130
+ # subkey1 value1
131
+ # subkey2 value2
132
+ #
133
+ # @param key [String] the key
134
+ # @param value [Hash] hash of values to display
135
+ # @param size [Integer] the size of the parent array, if there
136
+ # is one
137
+ # @param index [Integer] the index of this element in parent
138
+ # array, if there is one.
139
+ # @return [Nil]
140
+ #
141
+ def add_hash(key, value, arr_size = 0, arr_index = 0)
142
+ add_line(key) if arr_index.zero?
143
+ @indent += indent_step
144
+ @kw -= 2
145
+ _two_columns([value], kw - indent_step)
146
+ add_rule(kw) if arr_index + 1 < arr_size
147
+ end
148
+
149
+ # Add a horizontal rule, from the start of the second column to
150
+ # just shy of the end of the terminal
151
+ #
152
+ def add_rule(kw)
153
+ add_line(nil, '-' * (TW - kw - 4))
154
+ end
155
+
156
+ # Make the string which is prepended to each line. Stepping is
157
+ # controlled by @indent_step.
158
+ #
159
+ # @param indent [Integer] how many characters to indent by.
160
+ #
161
+ def mk_indent(indent)
162
+ @indent_str = ' ' * indent
163
+ end
164
+
165
+ # Print a single line of output, handling the necessary
166
+ # indentation and tabulation.
167
+ #
168
+ # @param key [String] what to print in the first (key) column.
169
+ # Make this an empty string to print
170
+ # @param val [String, Numeric] what to print in the second column
171
+ # @param tw [Integer] terminal width
172
+ #
173
+ def mk_line(key, value = '', tw = TW)
174
+ return indent_str + ' ' * kw + value if !key || key.empty?
175
+
176
+ indent_str + format("%-#{kw}s%s", key, value)
177
+ .fold(tw, kw + indent_str.size, '').rstrip
178
+ end
179
+
180
+ # Add a line, prepped by #mk_line() to the out array.
181
+ #
182
+ def add_line(*args)
183
+ @out.<< mk_line(*args)
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,55 @@
1
+ require_relative './base'
2
+
3
+ module WavefrontDisplayPrinter
4
+
5
+ # Print things which are per-row. The terse listings, primarily
6
+ #
7
+ class Terse < Base
8
+ attr_reader :data, :keys, :fmt_string
9
+
10
+ def initialize(data, *keys)
11
+ # require 'json'
12
+ # File.open('/tmp/1', 'w') { |f| f.puts data.to_json }
13
+ @data = data
14
+ @keys = keys
15
+ @fmt_string = format_string.rstrip
16
+ @out = prep_output
17
+ end
18
+
19
+ # @return [String] a Ruby format string for each line
20
+ #
21
+ def format_string
22
+ lk = longest_keys
23
+ keys.each_with_object('') { |k, out| out.<< "%-#{lk[k]}s " }
24
+ end
25
+
26
+ # Find the length of the longest value for each member of @keys,
27
+ # in @data.
28
+ #
29
+ # @return [Hash] with the same keys as :keys and Integer values
30
+ #
31
+ def longest_keys
32
+ keys.each_with_object(Hash[*keys.map { |k| [k, 0] }.flatten]) \
33
+ do |k, aggr|
34
+ data.each do |obj|
35
+ val = obj[k]
36
+ val = val.join(', ') if val.is_a?(Array)
37
+ aggr[k] = val.size if val.size > aggr[k]
38
+ end
39
+ end
40
+ end
41
+
42
+ # Print multiple column output. This method does no word
43
+ # wrapping.
44
+ #
45
+ # @param keys [Symbol] the keys you want in the output. They
46
+ # will be printed in the order given.
47
+ #
48
+ def prep_output
49
+ data.each_with_object([]) do |o, aggr|
50
+ args = keys.map { |k| o[k].is_a?(Array) ? o[k].join(', ') : o[k] }
51
+ aggr.<< format(fmt_string, *args).rstrip
52
+ end
53
+ end
54
+ end
55
+ end
@@ -6,7 +6,6 @@ module WavefrontDisplay
6
6
  #
7
7
  class Query < Base
8
8
  def do_default
9
-
10
9
  ts = if data.key?(:timeseries)
11
10
  data[:timeseries].each do |s|
12
11
  s[:data] = humanize_series(s[:data])
@@ -62,7 +61,7 @@ module WavefrontDisplay
62
61
  date, time = ht.split
63
62
  ds = date == last_date ? '' : date
64
63
  last_date = date
65
- format('%12s %s %s', ds, time, val)
64
+ format('%-12s %s %s', ds, time, val)
66
65
  end
67
66
  end
68
67
  end
@@ -11,7 +11,7 @@ module WavefrontDisplay
11
11
  end
12
12
 
13
13
  def do_list_brief
14
- terse_output(:id, :entityType)
14
+ multicolumn(:id, :entityType)
15
15
  end
16
16
  end
17
17
  end
@@ -12,13 +12,17 @@ module WavefrontDisplay
12
12
 
13
13
  def do_list_brief
14
14
  drop_cluster_sources
15
- terse_output(:id, :description)
15
+ multicolumn(:id, :description)
16
16
  end
17
17
 
18
- # Filter out the Wavefront cluster sources
18
+ def do_search_brief
19
+ multicolumn(:id)
20
+ end
21
+
22
+ # Filter out the Wavefront cluster sources. Don't sort them, or
23
+ # using offset and cursor becomes confusing.
19
24
  #
20
25
  def drop_cluster_sources
21
- data.sort_by! { |k, _v| k }
22
26
  return if options[:all]
23
27
  data.delete_if { |k| k.id =~ /prod-[\da-f]{2}-/ }
24
28
  end
@@ -6,13 +6,12 @@ module WavefrontDisplay
6
6
  #
7
7
  class Webhook < Base
8
8
  def do_list
9
- long_output([:id, :description, :createdEpochMillis,
10
- :updatedEpochMillis, :updaterId, :creatorId,
11
- :title])
9
+ long_output([:id, :title, :description, :createdEpochMillis,
10
+ :updatedEpochMillis, :updaterId, :creatorId])
12
11
  end
13
12
 
14
13
  def do_list_brief
15
- terse_output(:id, :title)
14
+ multicolumn(:id, :title)
16
15
  end
17
16
 
18
17
  def do_describe
@@ -1,6 +1,7 @@
1
1
  require 'fileutils'
2
2
  require 'wavefront-sdk/mixins'
3
3
  require_relative './base'
4
+ require 'open3'
4
5
 
5
6
  EVENT_STATE_DIR = Pathname.new('/var/tmp/wavefront')
6
7
 
@@ -26,7 +27,7 @@ module WavefrontCli
26
27
  options[:start] = Time.now - 600 unless options[:start]
27
28
  options[:end] = Time.now unless options[:end]
28
29
  wf.list(options[:start], options[:end], options[:limit] || 100,
29
- options[:offset] || nil)
30
+ options[:cursor] || nil)
30
31
  end
31
32
 
32
33
  def do_update
@@ -34,32 +35,37 @@ module WavefrontCli
34
35
  wf.update(options[:'<id>'], k => v)
35
36
  end
36
37
 
37
- def do_create
38
- options[:start] = Time.now unless options[:start]
38
+ # You can override the options generated by docopt. This is how
39
+ # #wrap() works.
40
+ #
41
+ def do_create(opts = nil)
42
+ opts ||= options
43
+
44
+ opts[:start] = Time.now unless opts[:start]
39
45
 
40
- t_start = parse_time(options[:start], true)
41
- id = [t_start, options[:'<event>']].join(':')
46
+ t_start = parse_time(opts[:start], true)
47
+ id = [t_start, opts[:'<event>']].join(':')
42
48
 
43
- body = { name: options[:'<event>'],
49
+ body = { name: opts[:'<event>'],
44
50
  startTime: t_start,
45
51
  id: id,
46
52
  annotations: {} }
47
53
 
48
- body[:annotations][:details] = options[:desc] if options[:desc]
49
- body[:annotations][:severity] = options[:severity] if options[:severity]
50
- body[:annotations][:type] = options[:type] if options[:type]
51
- body[:hosts] = options[:host] if options[:host]
54
+ body[:annotations][:details] = opts[:desc] if opts[:desc]
55
+ body[:annotations][:severity] = opts[:severity] if opts[:severity]
56
+ body[:annotations][:type] = opts[:type] if opts[:type]
57
+ body[:hosts] = opts[:host] if opts[:host]
52
58
 
53
- if options[:instant]
59
+ if opts[:instant]
54
60
  body[:endTime] = t_start + 1
55
- elsif options[:end]
56
- body[:endTime] = parse_time(options[:end], true)
61
+ elsif opts[:end]
62
+ body[:endTime] = parse_time(opts[:end], true)
57
63
  end
58
64
 
59
65
  resp = wf.create(body)
60
66
 
61
- unless options[:nostate] || options[:end] || options[:instant]
62
- create_state_file(id, options[:host])
67
+ unless opts[:nostate] || opts[:end] || opts[:instant]
68
+ create_state_file(id, opts[:host])
63
69
  end
64
70
 
65
71
  resp
@@ -71,19 +77,20 @@ module WavefrontCli
71
77
  # name, we'll look for something on the stack. If it does look
72
78
  # like a real event, we'll make and API call straight away.
73
79
  #
74
- def do_close
80
+ def do_close(id = nil)
81
+ id ||= options[:'<id>']
75
82
  ev_file = nil
76
83
 
77
- ev = if options[:'<id>'] == false
84
+ ev = if !id
78
85
  pop_event
79
- elsif options[:'<id>'] =~ /^\d{13}:.+/
80
- ev_file = state_dir + options[:'<id>']
81
- options[:'<id>']
86
+ elsif id =~ /^\d{13}:.+/
87
+ ev_file = state_dir + id
88
+ id
82
89
  else
83
- pop_event(options[:'<id>'])
90
+ pop_event(id)
84
91
  end
85
92
 
86
- abort "No locally stored event matches '#{options[:'<id>']}'." unless ev
93
+ abort "No locally stored event matches '#{id}'." unless ev
87
94
 
88
95
  res = wf.close(ev)
89
96
  ev_file.unlink if ev_file && ev_file.exist? && res.status.code == 200
@@ -106,14 +113,46 @@ module WavefrontCli
106
113
  exit
107
114
  end
108
115
 
116
+ def do_wrap
117
+ create_opts = options
118
+ create_opts[:desc] ||= create_opts[:command]
119
+ event_id = do_create(create_opts).response.id
120
+ exit_code = run_wrapped_cmd(options[:command])
121
+ do_close(event_id)
122
+ puts "Command exited #{exit_code}"
123
+ exit exit_code
124
+ end
125
+
109
126
  private
110
127
 
128
+ # Run a command, stream stderr and stdout to the screen (they
129
+ # get combined -- could be an issue for someone somewhere) and
130
+ # return the command's exit code
131
+ #
132
+ # rubocop:disable Lint/AssignmentInCondition
133
+ #
134
+ def run_wrapped_cmd(cmd)
135
+ puts 'Command output follows, on STDERR:'
136
+ puts '-' * (TW - 4)
137
+ ret = nil
138
+
139
+ Open3.popen2e(cmd) do |_in, out, thr|
140
+ while l = out.gets
141
+ STDERR.puts l
142
+ end
143
+
144
+ ret = thr.value.exitstatus
145
+ end
146
+
147
+ puts '-' * (TW - 4)
148
+ ret
149
+ end
150
+
111
151
  # Write a state file. We put the hosts bound to the event into the
112
152
  # file. These aren't currently used by anything in the CLI, but they
113
153
  # might be useful to someone, somewhere, someday.
114
154
  #
115
155
  def create_state_file(id, hosts = [])
116
- puts "statfile fir #{id}"
117
156
  fname = state_dir + id
118
157
 
119
158
  begin
@@ -1,5 +1,5 @@
1
1
  module WavefrontCli
2
2
  class Exception
3
- class UnhandledCommand < ::Exception; end
3
+ class UnhandledCommand < RuntimeError; end
4
4
  end
5
5
  end
@@ -37,13 +37,13 @@ module WavefrontCli
37
37
  @opts = DEFAULT_OPTS.merge(load_profile).merge(@cli_opts)
38
38
  end
39
39
 
40
+ # Load in configuration options from the (optionally) given
41
+ # section of an ini-style configuration file. If the file's not
42
+ # there, we don't consider that an error. Returns a hash of
43
+ # options which matches what Docopt gives us.
44
+ #
45
+ # rubocop:disable Metrics/AbcSize
40
46
  def load_profile
41
- #
42
- # Load in configuration options from the (optionally) given
43
- # section of an ini-style configuration file. If the file's
44
- # not there, we don't consider that an error. Returns a hash
45
- # of options which matches what Docopt gives us.
46
- #
47
47
  unless conf_file.exist?
48
48
  puts "config file '#{conf_file}' not found. Taking options " \
49
49
  'from command-line.'
@@ -19,11 +19,11 @@ module WavefrontCli
19
19
  sorted: true
20
20
  }
21
21
 
22
- if options[:start]
23
- options[:start] = parse_time(options[:start], true)
24
- else
25
- options[:start] = (Time.now - 600).to_i
26
- end
22
+ options[:start] = if options[:start]
23
+ parse_time(options[:start], true)
24
+ else
25
+ (Time.now - 600).to_i
26
+ end
27
27
 
28
28
  if options[:end]
29
29
  options[:end] = parse_time(options[:end], true)
@@ -42,7 +42,6 @@ module WavefrontCli
42
42
  options[:start], options[:end] || nil, opts)
43
43
  end
44
44
 
45
-
46
45
  # Work out a sensible granularity based on the time window
47
46
  #
48
47
  def default_granularity(window)
@@ -5,6 +5,10 @@ module WavefrontCli
5
5
  # CLI coverage for the v2 'source' API.
6
6
  #
7
7
  class Source < WavefrontCli::Base
8
+ def do_list
9
+ wf.list(options[:limit], options[:cursor])
10
+ end
11
+
8
12
  def do_clear
9
13
  wf.delete(options[:'<id>'])
10
14
  end
@@ -14,7 +18,7 @@ module WavefrontCli
14
18
  end
15
19
 
16
20
  def do_description_clear
17
- wf.update(options[:'<id>'], { description: ''}, false)
21
+ wf.update(options[:'<id>'], { description: '' }, false)
18
22
  end
19
23
  end
20
24
  end
@@ -0,0 +1,59 @@
1
+ # Extensions to the String class to help with formatting.
2
+ #
3
+ class String
4
+ # Fold long command lines. We can't break on a space after an
5
+ # option or it confuses docopt.
6
+ #
7
+ # @param tw [Integer] terminal width
8
+ # @param indent [Integer] size of hanging indent, in chars
9
+ #
10
+ def cmd_fold(tw = TW, indent = 10)
11
+ #gsub(/\s(?=\w+\])/, '^').scan_line(tw - 8).join("\n" + ' ' * indent)
12
+ gsub(/(-\w) /, "\\1^").scan_line(tw - 12).join("\n" + ' ' * indent)
13
+ .tr('^', ' ')
14
+ end
15
+
16
+ # Wrapper around #fold()
17
+ #
18
+ # @param tw [Integer] width of terminal, in chars
19
+ # @param indent [Integer] hanging indent of following lines
20
+ # @return [String] folded and indented string
21
+ #
22
+ def opt_fold(tw = TW, indent = 10)
23
+ fold(tw, indent, ' ')
24
+ end
25
+
26
+ # Fold long lines with a hanging indent. Originally a special case
27
+ # for option folding, now addded the prefix parameter to make it
28
+ # more general.
29
+ #
30
+ # rubocop:disable Metrics/AbcSize
31
+ #
32
+ # @param tw [Integer] terminal width
33
+ # @param indent [Integer] size of hanging indent, in chars
34
+ # @param prefix [String] prepended to every line
35
+ # @return [String] the folded line
36
+ #
37
+ def fold(tw = TW, indent = 10, prefix = '')
38
+ chunks = self.scan_line(tw - 8)
39
+
40
+ line_1 = prefix + chunks.shift + "\n"
41
+
42
+ return line_1 if chunks.empty?
43
+
44
+ rest = chunks.join(' ').scan_line(tw - indent - 5).map do |l|
45
+ prefix + ' ' * indent + l
46
+ end
47
+
48
+ line_1 + rest.join("\n") + "\n"
49
+ end
50
+
51
+ # @param width [Integer] length of longest string (width of
52
+ # terminal less some margin)
53
+ # @return [Array] original string chunked into an array width
54
+ # elements whose length < width
55
+ #
56
+ def scan_line(width)
57
+ scan(/\S.{0,#{width}}\S(?=\s|$)|\S+/)
58
+ end
59
+ end
@@ -1 +1 @@
1
- WF_CLI_VERSION = '0.0.5'.freeze
1
+ WF_CLI_VERSION = '1.0.0'.freeze
@@ -5,6 +5,7 @@ module WavefrontCli
5
5
  #
6
6
  # Send points to a proxy.
7
7
  #
8
+ # rubocop:disable Metrics/ClassLength
8
9
  class Write < Base
9
10
  attr_reader :fmt
10
11
  include Wavefront::Mixins
@@ -13,6 +14,8 @@ module WavefrontCli
13
14
  { proxy: options[:proxy], port: options[:port] || 2878 }
14
15
  end
15
16
 
17
+ # rubocop:disable Metrics/AbcSize
18
+ # rubocop:disable Metrics/MethodLength
16
19
  def do_point
17
20
  p = { path: options[:'<metric>'],
18
21
  value: options[:'<value>'].to_f,
@@ -152,7 +155,7 @@ module WavefrontCli
152
155
  # Merge them, making the -T win if there is a collision.
153
156
  #
154
157
  def line_tags(chunks)
155
- file_tags = fmt.last == 'T' ? extract_tags(chunks) : {}
158
+ file_tags = fmt.last == 'T' ? extract_tags(chunks) : {}
156
159
  opt_tags = tags_to_hash(options[:tag])
157
160
  file_tags.merge(opt_tags)
158
161
  end
data/spec/spec_helper.rb CHANGED
@@ -50,7 +50,7 @@ def cmd_to_call(word, args, call, sdk_class = nil)
50
50
  headers = { 'Accept': /.*/,
51
51
  'Accept-Encoding': /.*/,
52
52
  'Authorization': 'Bearer 0123456789-ABCDEF',
53
- 'User-Agent': /wavefront-sdk .*/,
53
+ 'User-Agent': "wavefront-cli-#{WF_CLI_VERSION}"
54
54
  }
55
55
 
56
56
  sdk_class ||= Object.const_get("WavefrontCli::#{word.capitalize}")
@@ -18,19 +18,30 @@ describe "#{word} command" do
18
18
 
19
19
  it 'deletes with a check on inTrash' do
20
20
  stub_request(:get,
21
- 'https://other.wavefront.com/api/v2/alert/1481553823153').
22
- with(headers: {'Accept': '*/*',
23
- 'Accept-Encoding': 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
21
+ 'https://other.wavefront.com/api/v2/alert/1481553823153')
22
+ .with(headers: { 'Accept': '*/*',
23
+ 'Accept-Encoding':
24
+ 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
24
25
  'Authorization': 'Bearer 0123456789-ABCDEF',
25
- 'User-Agent': /wavefront.*/}).
26
- to_return(:status => 200, :body => "", :headers => {})
26
+ 'User-Agent': /wavefront.*/ })
27
+ .to_return(status: 200, body: '', headers: {})
27
28
  cmd_to_call(word, "delete #{id}",
28
29
  method: :delete, path: "/api/v2/#{word}/#{id}")
29
30
  end
31
+
30
32
  cmd_to_call(word, "undelete #{id}",
31
33
  method: :post, path: "/api/v2/#{word}/#{id}/undelete")
32
34
  cmd_to_call(word, "snooze #{id}",
33
35
  method: :post, path: "/api/v2/#{word}/#{id}/snooze")
36
+ cmd_to_call(word, "search id=#{id}",
37
+ { method: :post, path: "/api/v2/search/#{word}",
38
+ body: { limit: 10,
39
+ offset: 0,
40
+ query: [{key: 'id',
41
+ value: id,
42
+ matchingMethod: 'EXACT'}],
43
+ sort: {field: 'id', ascending: true}},
44
+ headers: JSON_POST_HEADERS })
34
45
  cmd_to_call(word, "snooze -T 800 #{id}",
35
46
  method: :post,
36
47
  path: "/api/v2/#{word}/#{id}/snooze?seconds=800")