wavefront-cli 2.12.0 → 2.13.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d78c82e2fafc2ac41fd155095a99fbc63b33b377296aa67ee1f0ed1cb3252c46
4
- data.tar.gz: 2ef97b05806363fd93fc72068af3f662d1eb6c5828a2a319d429844f8e717e6e
3
+ metadata.gz: c9007cbf188f6962a31b04002c5b64c86e85bbc2ddad05e5299647706970ad65
4
+ data.tar.gz: 6b5daf8e04b6d5090837620f51dc9e1b5ce3c9d45227fe66d118a2adb94e758b
5
5
  SHA512:
6
- metadata.gz: f7646c92517c80068758780b69b01e385ff7de1bf62efb49003240a60a33af4b85a5c3d220a78f1573588bbe53e7d3236d7ef00741b17d3db033dc848f14f0cb
7
- data.tar.gz: 21566d131e3064522a1583c3ae44b57b38b277b521edb5336d8d58cfed606e673fe3b9f7d4036882a7a314db60a1726f4204aed08c1152dea181c00ac64d5837
6
+ metadata.gz: c224961d3690bed9d069d689d632c726262342ad4cc278b1942d4e70cc54a4263e0d89eda027b156cd93fde9184db04f831f75cbad3fe374f5a45f3eb7f30769
7
+ data.tar.gz: 2b20581ec22ae10242eea44ff07862b43eeb5bac057774b56aa6f3a363379298dbaca416859d1c274770edb376fe4bf3f85484876e16db23a475c457b850ac1b
data/HISTORY.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.13.0 (11/12/2018)
4
+ * Add CSV output for `query` command.
5
+ * Add multiple format outputs for all applicable `alert`
6
+ subcommands.
7
+ * Add `queries` subcommand for `alert` and `dashboard` subcommands,
8
+ to quickly see which queries (and therefore timeseries) are being
9
+ used.
10
+
3
11
  ## 2.12.0 (26/11/2018)
4
12
  * Support SDK's new `unix` writer, which lets you write points to a
5
13
  local Unix datagram socket. This requires `-u unix` and `-S
@@ -54,6 +54,12 @@ module WavefrontCli
54
54
  in_state(:firing)
55
55
  end
56
56
 
57
+ def do_queries
58
+ wf.list(0, :all).tap do |r|
59
+ r.response.items.map! { |a| { id: a.id, condition: a.condition } }
60
+ end
61
+ end
62
+
57
63
  # How many alerts are in the given state? If none, say so,
58
64
  # rather than just printing nothing.
59
65
  #
@@ -9,8 +9,8 @@ class WavefrontCommandAlert < WavefrontCommandBase
9
9
 
10
10
  def _commands
11
11
  ["list #{CMN} [-al] [-f format] [-o offset] [-L limit]",
12
- "firing #{CMN} [-o offset] [-L limit]",
13
- "snoozed #{CMN} [-o offset] [-L limit]",
12
+ "firing #{CMN} [-f format] [-o offset] [-L limit]",
13
+ "snoozed #{CMN} [-f format] [-o offset] [-L limit]",
14
14
  "describe #{CMN} [-f format] [-v version] <id>",
15
15
  "delete #{CMN} <id>",
16
16
  "undelete #{CMN} <id>",
@@ -25,8 +25,9 @@ class WavefrontCommandAlert < WavefrontCommandBase
25
25
  "tag clear #{CMN} <id>",
26
26
  "tag add #{CMN} <id> <tag>",
27
27
  "tag delete #{CMN} <id> <tag>",
28
- "currently #{CMN} <state>",
29
- "summary #{CMN} [-a]"]
28
+ "currently #{CMN} [-f format] <state>",
29
+ "queries #{CMN} [-f format] [-b]",
30
+ "summary #{CMN} [-f format] [-a]"]
30
31
  end
31
32
 
32
33
  def _options
@@ -37,6 +38,7 @@ class WavefrontCommandAlert < WavefrontCommandBase
37
38
  '-o, --offset=n start from nth alert',
38
39
  '-L, --limit=COUNT number of alerts to list',
39
40
  '-T, --time=SECONDS how long to snooze (default 3600)',
41
+ '-b, --brief do not show alert names',
40
42
  '-f, --format=STRING output format']
41
43
  end
42
44
  end
@@ -16,6 +16,7 @@ class WavefrontCommandDashboard < WavefrontCommandBase
16
16
  "undelete #{CMN} <id>",
17
17
  "history #{CMN} [-f format] [-o offset] [-L limit] <id>",
18
18
  "search #{CMN} [-al] [-f format] [-o offset] [-L limit] <condition>...",
19
+ "queries #{CMN} [-f format] [-b]",
19
20
  tag_commands]
20
21
  end
21
22
 
@@ -26,6 +27,7 @@ class WavefrontCommandDashboard < WavefrontCommandBase
26
27
  '-o, --offset=n start list from nth dashboard or revision',
27
28
  '-L, --limit=COUNT number of dashboards or revisions to list',
28
29
  '-v, --version=INTEGER version of dashboard',
30
+ '-b, --brief do not show dashboard names',
29
31
  '-f, --format=STRING output format']
30
32
  end
31
33
  end
@@ -10,10 +10,11 @@ class WavefrontCommandQuery < WavefrontCommandBase
10
10
  def _commands
11
11
  ['aliases [-DV] [-c file] [-P profile]',
12
12
  "#{CMN} [-g granularity] [-s time] [-e time] [-f format] " \
13
- '[-WikvO] [-S mode] [-N name] [-p points] <query>',
14
- "raw #{CMN} [-H host] [-s time] [-e time] [-f format] <metric>",
13
+ '[-WikvO] [-S mode] [-N name] [-p points] [-F options] <query>',
14
+ "raw #{CMN} [-H host] [-s time] [-e time] [-f format] " \
15
+ '[-F options] <metric>',
15
16
  "run #{CMN} [-g granularity] [-s time] [-e time] [-f format] " \
16
- '[-WkivO] [-S mode] [-N name] [-p points] <alias>']
17
+ '[-F options] [-WkivO] [-S mode] [-N name] [-p points] <alias>']
17
18
  end
18
19
 
19
20
  def _options
@@ -31,6 +32,8 @@ class WavefrontCommandQuery < WavefrontCommandBase
31
32
  '-O, --obsolete include metrics unreported for > 4 weeks',
32
33
  '-H, --host=STRING host or source to query on',
33
34
  '-f, --format=STRING output format',
35
+ '-F, --format-opts=STRING comma-separated options to pass to ' \
36
+ 'output formatter',
34
37
  '-k, --nospark do not show sparkline',
35
38
  '-W, --nowarn do not show API warning messages']
36
39
  end
@@ -38,6 +41,9 @@ class WavefrontCommandQuery < WavefrontCommandBase
38
41
  def postscript
39
42
  'The query command has an additional output format. Using ' \
40
43
  "'-f wavefront' produces output suitable for feeding back into a " \
41
- 'proxy.'.cmd_fold(TW, 0)
44
+ "proxy. Other output formats are 'yaml', 'json', 'ruby', "\
45
+ "and 'csv'. CSV format options are 'header' (print column headers); " \
46
+ "'tagkeys' (print tags as key=value rather than value); and 'quote' " \
47
+ '(force quoting of every CSV element).'.cmd_fold(TW, 0)
42
48
  end
43
49
  end
@@ -23,5 +23,36 @@ module WavefrontCli
23
23
  def do_history
24
24
  wf.history(options[:'<id>'])
25
25
  end
26
+
27
+ def do_queries
28
+ resp = wf.list(0, :all)
29
+
30
+ queries = resp.response.items.each_with_object({}) do |d, a|
31
+ a[d.id] = extract_values(d, 'query')
32
+ end
33
+
34
+ resp.tap { |r| r.response.items = queries }
35
+ end
36
+
37
+ # @param obj [Object] the thing to search
38
+ # @param key [String, Symbol] the key to search for
39
+ # @param aggr [Array] values of matched keys
40
+ # @return [Array]
41
+ #
42
+ def extract_values(obj, key, aggr = [])
43
+ if obj.is_a?(Hash)
44
+ obj.each_pair do |k, v|
45
+ if k == key && !v.to_s.empty?
46
+ aggr.<< v
47
+ else
48
+ extract_values(v, key, aggr)
49
+ end
50
+ end
51
+ elsif obj.is_a?(Array)
52
+ obj.each { |e| extract_values(e, key, aggr) }
53
+ end
54
+
55
+ aggr
56
+ end
26
57
  end
27
58
  end
@@ -55,5 +55,13 @@ module WavefrontDisplay
55
55
  data.sort.each { |k, v| puts format("%-#{kw}s%s", k, v) }
56
56
  end
57
57
  # rubocop:enable Metrics/AbcSize
58
+
59
+ def do_queries
60
+ if options[:brief]
61
+ multicolumn(:condition)
62
+ else
63
+ multicolumn(:id, :condition)
64
+ end
65
+ end
58
66
  end
59
67
  end
@@ -220,6 +220,14 @@ module WavefrontDisplay
220
220
  end
221
221
  end
222
222
 
223
+ def do_queries
224
+ if options[:brief]
225
+ multicolumn(:condition)
226
+ else
227
+ multicolumn(:id, :condition)
228
+ end
229
+ end
230
+
223
231
  # Modify, in-place, the data structure to remove fields which
224
232
  # we deem not of interest to the user.
225
233
  #
@@ -17,5 +17,14 @@ module WavefrontDisplay
17
17
  data[:sections] = data[:sections].map { |s| s[:name] }
18
18
  long_output
19
19
  end
20
+
21
+ def do_queries
22
+ if options[:brief]
23
+ @data = data.to_h.values.flatten.map { |q| { query: q } }
24
+ multicolumn(:query)
25
+ else
26
+ long_output
27
+ end
28
+ end
20
29
  end
21
30
  end
@@ -17,6 +17,7 @@ module WavefrontDisplayPrinter
17
17
  # @return [String] a Ruby format string for each line
18
18
  #
19
19
  def format_string
20
+ return '%s' if keys.length == 1
20
21
  lk = longest_keys
21
22
  keys.each_with_object('') { |k, out| out.<< "%-#{lk[k]}s " }
22
23
  end
@@ -0,0 +1,8 @@
1
+ require_relative 'base'
2
+
3
+ module WavefrontOutput
4
+ #
5
+ # Display query results in CSV format.
6
+ #
7
+ class Csv < Base; end
8
+ end
@@ -0,0 +1,18 @@
1
+ module WavefrontCsvOutput
2
+ #
3
+ # Standard output template
4
+ #
5
+ class Base
6
+ attr_reader :resp, :options
7
+
8
+ def initialize(resp, options)
9
+ @resp = resp
10
+ @options = options
11
+ post_initialize if respond_to?(:post_initialize)
12
+ end
13
+
14
+ def run
15
+ puts _run
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,117 @@
1
+ require 'set'
2
+ require_relative 'base'
3
+
4
+ module WavefrontCsvOutput
5
+ #
6
+ # Display query results in CSV format.
7
+ #
8
+ # The following options are supported:
9
+ # quote -- puts all values in soft quotes
10
+ # headers -- print CSV column headers
11
+ # tagkeys -- normally point tag keys go in the header and values in
12
+ # the CSV data. This option puts key=value in the CSV.
13
+ #
14
+ class Query < Base
15
+ attr_reader :columns, :formatopts, :headers, :data_map
16
+
17
+ def _run
18
+ csv_headers + csv_body
19
+ end
20
+
21
+ def post_initialize
22
+ @headers = []
23
+ @formatopts = extract_formatopts
24
+ @data_map = options[:raw] ? raw_output : query_output
25
+ @columns = all_keys.freeze
26
+ end
27
+
28
+ # @return [Array[Hash]] which goes in the @data_map
29
+ #
30
+ def raw_output
31
+ resp.each_with_object([]) do |point, a|
32
+ point[:points].each do |p|
33
+ a.<< csv_format(options[:'<metric>'],
34
+ p[:value],
35
+ p[:timestamp],
36
+ options[:host],
37
+ point[:tags])
38
+ end
39
+ end
40
+ end
41
+
42
+ # @return [Array[Hash]] which goes in the @data_map
43
+ #
44
+ def query_output
45
+ resp[:timeseries].each_with_object([]) do |ts, a|
46
+ ts[:data].each do |point|
47
+ a.<< csv_format(ts[:label],
48
+ point[1],
49
+ point[0],
50
+ ts[:host],
51
+ ts[:tags])
52
+ end
53
+ end
54
+ end
55
+
56
+ # @return [Array] unique list of all keys in an array of hashes
57
+ #
58
+ def all_keys(data = data_map)
59
+ data.each_with_object(Set.new) { |row, a| a.merge(row.keys) }.to_a
60
+ end
61
+
62
+ # @return [Array] single element of comma-separated CSV column
63
+ # headers if requested, otherwise []
64
+ #
65
+ def csv_headers
66
+ return [] unless formatopts.include?('headers')
67
+ [columns.map { |c| csv_value(c) }.join(',')]
68
+ end
69
+
70
+ def csv_body
71
+ data_map.map { |r| map_row_to_csv(r) }
72
+ end
73
+
74
+ def map_row_to_csv(row)
75
+ columns.map { |col| csv_value(row[col]) }.join(',')
76
+ end
77
+
78
+ # Do escaping and quoting
79
+ #
80
+ def csv_value(value)
81
+ if (formatopts.include?('quote') || value =~ /[,\s"]/) &&
82
+ !value.to_s.empty?
83
+ quote_value(value)
84
+ else
85
+ value
86
+ end
87
+ end
88
+
89
+ def quote_value(value)
90
+ format('"%s"', value.to_s.gsub(/"/, '\"'))
91
+ end
92
+
93
+ # Turn a string of output options into an easy-to-query array
94
+ #
95
+ def extract_formatopts
96
+ options[:formatopts].nil? ? [] : options[:formatopts].split(',')
97
+ end
98
+
99
+ # Take the data describing a point, and turn it into a CSV row.
100
+ # Tags have their keys removed.
101
+ #
102
+ def csv_format(path, value, timestamp, source, tags = nil)
103
+ ret = { path: path,
104
+ value: value,
105
+ timestamp: timestamp,
106
+ source: source }
107
+
108
+ ret.tap { |r| tags.each { |k, v| r[k.to_sym] = tag_val(k, v) } }
109
+ end
110
+
111
+ # We may be doing key=val or just val, depending on the formatter options
112
+ #
113
+ def tag_val(key, val)
114
+ formatopts.include?('tagkeys') ? format('%s=%s', key, val) : val
115
+ end
116
+ end
117
+ end
@@ -1 +1 @@
1
- WF_CLI_VERSION = '2.12.0'.freeze
1
+ WF_CLI_VERSION = '2.13.0'.freeze
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../../../spec_helper'
4
+ require_relative '../../../../lib/wavefront-cli/output/csv/query'
5
+
6
+ # Test CSV output
7
+ #
8
+ class WavefrontOutputCsvTest < MiniTest::Test
9
+ attr_reader :wfq, :wfr, :wfqq, :wfh, :wft
10
+
11
+ def setup
12
+ @wfq = WavefrontCsvOutput::Query.new(load_query_response, {})
13
+ @wfr = WavefrontCsvOutput::Query.new(
14
+ load_raw_query_response,
15
+ raw: true,
16
+ host: 'www-blue',
17
+ '<metric>': 'solaris.network.obytes64'
18
+ )
19
+ @wfqq = WavefrontCsvOutput::Query.new(load_query_response,
20
+ formatopts: 'quote')
21
+ @wfh = WavefrontCsvOutput::Query.new(load_query_response,
22
+ formatopts: 'headers')
23
+ @wft = WavefrontCsvOutput::Query.new(load_query_response,
24
+ formatopts: 'tagkeys')
25
+ end
26
+
27
+ def test_all_keys
28
+ assert_equal(%i[a b c d e],
29
+ wfq.all_keys([{ a: 1, b: 2 }, { a: 3, c: 3 },
30
+ { d: 4, e: 5 }, { a: 1 }]))
31
+ end
32
+
33
+ def test_csv_value
34
+ assert_equal('word', wfq.csv_value('word'))
35
+ assert_equal('"word"', wfqq.csv_value('word'))
36
+ assert_equal('"7\" single"', wfq.quote_value('7" single'))
37
+ assert_equal('"7\" single"', wfqq.quote_value('7" single'))
38
+ assert_equal('"two words"', wfq.quote_value('two words'))
39
+ assert_equal('"two words"', wfqq.quote_value('two words'))
40
+ assert_equal('"a, b"', wfq.quote_value('a, b'))
41
+ assert_equal('"a, b"', wfqq.quote_value('a, b'))
42
+ end
43
+
44
+ def test_quote_value
45
+ assert_equal('"word"', wfq.quote_value('word'))
46
+ assert_equal('"1"', wfr.quote_value(1))
47
+ assert_equal('"two words"', wft.quote_value('two words'))
48
+ assert_equal('"7\" single"', wfh.quote_value('7" single'))
49
+ end
50
+
51
+ def test_csv_headers
52
+ assert_empty(wfq.csv_headers)
53
+ wfh = WavefrontCsvOutput::Query.new(load_query_response,
54
+ formatopts: 'headers')
55
+ assert_equal(['path,value,timestamp,source,colour,environment,' \
56
+ 'product,role,nic,platform,dc'], wfh.csv_headers)
57
+ end
58
+
59
+ def test_map_row_to_csv
60
+ assert_equal(',,,,,,,,,,', wfq.map_row_to_csv(merp: 1))
61
+ assert_equal('test.path,1,1544529523,testsource,,"unit test",,,,,',
62
+ wfq.map_row_to_csv(path: 'test.path',
63
+ value: 1,
64
+ timestamp: 1_544_529_523,
65
+ source: 'testsource',
66
+ environment: 'unit test'))
67
+ assert_equal('"test.path","1","1544529523","testsource",,"unit test",,,,,',
68
+ wfqq.map_row_to_csv(path: 'test.path',
69
+ value: 1,
70
+ timestamp: 1_544_529_523,
71
+ source: 'testsource',
72
+ environment: 'unit test'))
73
+ end
74
+
75
+ def test_csv_format
76
+ assert_equal({ path: 'test.path',
77
+ value: 1,
78
+ timestamp: 1_544_529_523,
79
+ source: 'testsource',
80
+ environment: 'test',
81
+ dc: 'travis' },
82
+ wfq.csv_format('test.path', 1, 1_544_529_523, 'testsource',
83
+ environment: 'test', dc: 'travis'))
84
+
85
+ assert_equal({ path: 'test.path',
86
+ value: 1,
87
+ timestamp: 1_544_529_523,
88
+ source: 'testsource',
89
+ environment: 'environment=test',
90
+ dc: 'dc=travis' },
91
+ wft.csv_format('test.path', 1, 1_544_529_523, 'testsource',
92
+ environment: 'test', dc: 'travis'))
93
+ end
94
+
95
+ def test_tag_val
96
+ assert_equal('value', wfq.tag_val('key', 'value'))
97
+ assert_equal('value', wfr.tag_val('key', 'value'))
98
+ assert_equal('key=value', wft.tag_val('key', 'value'))
99
+ assert_equal('key=value', wft.tag_val(:key, :value))
100
+ end
101
+
102
+ def test__run_query
103
+ out_q = wfq._run
104
+ assert_equal(
105
+ 'solaris.network.obytes64,20910.38968253968,1533679200,' \
106
+ 'wavefront-blue,blue,production,websites,wavefront-proxy,net0,' \
107
+ 'JPC-triton,eu-ams-1', out_q.first
108
+ )
109
+ assert_equal(24, out_q.size)
110
+ check_csv_output(out_q)
111
+
112
+ out_h = wfh._run
113
+ assert_equal(
114
+ 'path,value,timestamp,source,colour,environment,product,role,' \
115
+ 'nic,platform,dc', out_h.first
116
+ )
117
+ assert_equal(
118
+ 'solaris.network.obytes64,20910.38968253968,1533679200,' \
119
+ 'wavefront-blue,blue,production,websites,wavefront-proxy,net0,' \
120
+ 'JPC-triton,eu-ams-1', out_h[1]
121
+ )
122
+ assert_equal(25, out_h.size)
123
+
124
+ out_t = wft._run
125
+ assert_equal(
126
+ 'solaris.network.obytes64,20910.38968253968,1533679200,' \
127
+ 'wavefront-blue,colour=blue,environment=production,product=websites,' \
128
+ 'role=wavefront-proxy,nic=net0,' \
129
+ 'platform=JPC-triton,dc=eu-ams-1', out_t.first
130
+ )
131
+ assert_equal(24, out_t.size)
132
+ check_csv_output(out_q)
133
+ end
134
+
135
+ def test__run_raw
136
+ check_csv_output(wfq._run)
137
+ end
138
+
139
+ def check_csv_output(out)
140
+ out.each do |l|
141
+ c = l.split(',', 5)
142
+ assert_equal(c[0], 'solaris.network.obytes64')
143
+ assert_match(/^[\d\.]+$/, c[1])
144
+ # query returns epoch s timestamp, raw returns epoch ms
145
+ assert_match(/^\d+$/, c[2])
146
+ assert(c[2].size == 10 || c[2].size == 13)
147
+ assert(c[3] =~ /.*blue$/)
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../../spec_helper'
4
+ require_relative '../../../lib/wavefront-cli/output/csv'
5
+
6
+ # Test the CSV instantiation of the base class
7
+ #
8
+ class CsvOutputBaseTest < MiniTest::Test
9
+ attr_reader :wfo
10
+
11
+ def setup
12
+ @wfo = WavefrontOutput::Csv.new(load_query_response, class: 'query')
13
+ end
14
+
15
+ def test_my_format
16
+ assert('csv', wfo.my_format)
17
+ end
18
+
19
+ def test_command_class_name
20
+ assert_equal('WavefrontCsvOutput::Query', wfo.command_class_name)
21
+ end
22
+
23
+ def test_command_file
24
+ assert_equal('csv/query', wfo.command_file)
25
+ end
26
+
27
+ def test_command_class
28
+ supported_commands = %w[query]
29
+
30
+ supported_commands.each do |cmd|
31
+ wfo = WavefrontOutput::Csv.new(load_query_response, class: cmd)
32
+ klass = wfo.command_class
33
+ assert_equal("WavefrontCsvOutput::#{cmd.capitalize}",
34
+ klass.class.name)
35
+ assert klass.respond_to?(:run)
36
+ end
37
+
38
+ (CMDS - supported_commands).each do |cmd|
39
+ wfo = WavefrontOutput::Csv.new(load_query_response, class: cmd)
40
+ assert_raises(LoadError) { wfo.command_class }
41
+ end
42
+ end
43
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wavefront-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.12.0
4
+ version: 2.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Fisher
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-05 00:00:00.000000000 Z
11
+ date: 2018-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docopt
@@ -230,6 +230,9 @@ files:
230
230
  - lib/wavefront-cli/notificant.rb
231
231
  - lib/wavefront-cli/opt_handler.rb
232
232
  - lib/wavefront-cli/output/base.rb
233
+ - lib/wavefront-cli/output/csv.rb
234
+ - lib/wavefront-cli/output/csv/base.rb
235
+ - lib/wavefront-cli/output/csv/query.rb
233
236
  - lib/wavefront-cli/output/hcl.rb
234
237
  - lib/wavefront-cli/output/hcl/alert.rb
235
238
  - lib/wavefront-cli/output/hcl/base.rb
@@ -288,6 +291,8 @@ files:
288
291
  - spec/wavefront-cli/message_spec.rb
289
292
  - spec/wavefront-cli/metric_spec.rb
290
293
  - spec/wavefront-cli/opt_handler_spec.rb
294
+ - spec/wavefront-cli/output/csv/query_spec.rb
295
+ - spec/wavefront-cli/output/csv_spec.rb
291
296
  - spec/wavefront-cli/output/hcl_spec.rb
292
297
  - spec/wavefront-cli/output/json_spec.rb
293
298
  - spec/wavefront-cli/output/ruby_spec.rb
@@ -366,6 +371,8 @@ test_files:
366
371
  - spec/wavefront-cli/message_spec.rb
367
372
  - spec/wavefront-cli/metric_spec.rb
368
373
  - spec/wavefront-cli/opt_handler_spec.rb
374
+ - spec/wavefront-cli/output/csv/query_spec.rb
375
+ - spec/wavefront-cli/output/csv_spec.rb
369
376
  - spec/wavefront-cli/output/hcl_spec.rb
370
377
  - spec/wavefront-cli/output/json_spec.rb
371
378
  - spec/wavefront-cli/output/ruby_spec.rb