wavefront-cli 0.0.5 → 1.0.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.
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")