multiforecast-client 0.62.0.5 → 0.62.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1da64cc1b3b63ef49933d1f4ebf864a3cb4af295
4
- data.tar.gz: 7aaf9779934ec727c02a61696b37b2004d332554
3
+ metadata.gz: 0b9877d259aaf94156087bbac8bb9aa66694db1c
4
+ data.tar.gz: 187c70b320517e6df23d68877d9bd881b5f55c08
5
5
  SHA512:
6
- metadata.gz: d7faed48ecf007ddc67ea66dbf3919a35382ac3663d9fdf2e1f5a3443e068f1b1c8ffe4a16f05ef3abc7e4552c29703cfd18ba0c0d0a5ef71307182b8a6a36ed
7
- data.tar.gz: f3d947e1a93f8901e2edcc01dd650aa386b9f8704916a443afa39e5160bff0783d8d685a510732a5ffa2cfa9fe2d87a992359e18453831db6738e37f4fd9fd17
6
+ metadata.gz: ddc753bd90d278f704fc8aa87ee2e04fe4ce8e1b9aed7d11a21ed94912f17a47df6c98a7999d314261015d84d02f11cda1977341e760d866d8920c8e3ee036ca
7
+ data.tar.gz: 0cce09b837eb7a5cd5a1a04dbca59fe69a7cecd58da04d45129e202bca6c5d3cd0f3644fc4e1e315ceb84280697da59013b40f76b1c2b152200f1ec76d9b9e09
data/.gitignore CHANGED
@@ -12,3 +12,4 @@ tags
12
12
  tmp/*
13
13
  .yardoc
14
14
  multiforecast.yml
15
+ pkg
data/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
1
+ # 0.62.0.8 (2013/09/20)
2
+
3
+ Enhancements:
4
+
5
+ * Add `--graph-names` options to `delete` sub command
6
+
7
+ # 0.62.0.7 (2013/09/19)
8
+
9
+ Enhancements:
10
+
11
+ * Add `color` and `create_complex` sub command
12
+
13
+ # 0.62.0.6 (2013/09/18)
14
+
15
+ CHANGES
16
+
17
+ * Change the github repositry from sonots to yohoushi
18
+
19
+ # 0.62.0.5 (2013/07/27)
20
+
21
+ Fix
22
+
23
+ * Fix the `lstrip`
24
+
1
25
  # 0.62.0.4 (2013/07/25)
2
26
 
3
27
  CHANGES
@@ -8,7 +32,7 @@ CHANGES
8
32
 
9
33
  Fix
10
34
 
11
- * Escape a white space to %20, not + to avoid GF (Kossy?) bug
35
+ * Escape a white space to %20, not +.
12
36
 
13
37
  # 0.62.0.2 (2013/07/07)
14
38
 
data/README.md CHANGED
@@ -59,12 +59,24 @@ Post a number and create a graph:
59
59
  $ multiforecast post '{"number":0}' 'foo/a/b/c' -c multiforecast.yml
60
60
  ```
61
61
 
62
- Delete a graph or graphs under a path:
62
+ Delete a graph or graphs under a base path:
63
63
 
64
64
  ```
65
65
  $ multiforecast delete 'foo/' -c multiforecast.yml
66
66
  ```
67
67
 
68
+ Change the color of graphs under a base path:
69
+
70
+ ```
71
+ $ multiforecast color -k '2xx_count:#1111cc' '3xx_count:#11cc11' -b 'foo/' -c multiforecast.yml
72
+ ```
73
+
74
+ Create complex graphs under a base path:
75
+
76
+ ```
77
+ $ multiforecast create_complex -f 2xx_count 3xx_count -t status_count -b 'foo/' -c multiforecast.yml
78
+ ```
79
+
68
80
  See help for more:
69
81
 
70
82
  ```
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.62.0.5
1
+ 0.62.0.8
@@ -4,12 +4,14 @@ require 'yaml'
4
4
  require 'multiforecast-client'
5
5
 
6
6
  class MultiForecast::CLI < Thor
7
+ include ::MultiForecast::ConversionRule
7
8
  class_option :config, :aliases => ["-c"], :type => :string
8
9
  class_option :silent, :aliases => ["-S"], :type => :boolean
9
10
 
10
11
  def initialize(args = [], opts = [], config = {})
11
12
  super(args, opts, config)
12
13
 
14
+ # NOTE: Please note that @options receives only strings, no symbols anymore
13
15
  if options['config'] && File.exists?(options['config'])
14
16
  @options = YAML.load_file(options['config']).merge(@options)
15
17
  end
@@ -31,39 +33,114 @@ class MultiForecast::CLI < Thor
31
33
  long_desc <<-LONGDESC
32
34
  Post a parameter to a path
33
35
 
34
- ex)
35
- $ multiforecast post '{"number":0}' 'test/test' -c multiforecast.yml
36
+ ex) multiforecast post '{"number":0}' 'test/test' -c multiforecast.yml
36
37
  LONGDESC
37
38
  def post(json, path)
38
- begin
39
+ path = lstrip(path, '/')
40
+ exec do
39
41
  res = @client.post_graph(path, JSON.parse(json))
40
42
  $stdout.puts res unless @options['silent']
41
- rescue => e
42
- $stderr.puts "\tclass:#{e.class}\t#{e.message}"
43
43
  end
44
44
  end
45
45
 
46
+ # NOTE: base_path argument should be a requirement for foolproof
46
47
  desc 'delete <base_path>', 'Delete a graph or graphs under a path'
48
+ long_desc <<-LONGDESC
49
+ Delete a graph or graphs under a path
50
+
51
+ ex) multiforecast delete 'test/test' -c multiforecast.yml
52
+ LONGDESC
53
+ option :graph_names, :type => :array, :aliases => '-g'
47
54
  def delete(base_path)
55
+ base_path = lstrip(base_path, '/')
56
+
57
+ graphs = @client.list_graph(base_path)
58
+ delete_graphs(graphs, @options['graph_names'])
59
+
60
+ complexes = @client.list_complex(base_path)
61
+ delete_complexes(complexes, @options['graph_names'])
62
+ $stderr.puts "Not found" if graphs.empty? and complexes.empty? unless @options['silent']
63
+ end
64
+
65
+ desc 'color', 'change the color of graphs'
66
+ long_desc <<-LONGDESC
67
+ Change the color of graphs
68
+
69
+ ex) multiforecast color -k '2xx_count:#1111cc' '3xx_count:#11cc11' -c multiforecast.yml
70
+ LONGDESC
71
+ option :colors, :type => :hash, :aliases => '-k', :required => true, :banner => 'GRAPH_NAME:COLOR ...'
72
+ option :base_path, :type => :string, :aliases => '-b'
73
+ def color
74
+ base_path = lstrip(@options['base_path'], '/') if @options['base_path']
75
+ graphs = @client.list_graph(base_path)
76
+ setup_colors(@options['colors'], graphs)
77
+ end
78
+
79
+ desc 'create_complex', 'create complex graphs'
80
+ long_desc <<-LONGDESC
81
+ Create complex graphs under a url
82
+
83
+ ex) multiforecast create_complex -f 2xx_count 3xx_count -t status_count -c multiforecast.yml
84
+ LONGDESC
85
+ option :from_graphs, :type => :array, :aliases => '-f', :required => true, :banner => 'GRAPH_NAMES ...'
86
+ option :to_complex, :type => :string, :aliases => '-t', :required => true
87
+ option :base_path, :type => :string, :aliases => '-b'
88
+ def create_complex
89
+ base_path = lstrip(@options['base_path'], '/') if @options['base_path']
48
90
  graphs = @client.list_graph(base_path)
91
+ setup_complex(options['from_graphs'], options['to_complex'], graphs)
92
+ end
93
+
94
+ private
95
+
96
+ def delete_graphs(graphs, graph_names = nil)
49
97
  graphs.each do |graph|
50
- begin
51
- @client.delete_graph(graph['path'])
52
- $stdout.puts "Deleted #{graph['path']}" unless @options['silent']
53
- rescue => e
54
- $stderr.puts "\tclass:#{e.class}\t#{e.message}"
55
- end
98
+ path = graph['path']
99
+ next if graph_names and !graph_names.include?(File.basename(path))
100
+ puts "Delete #{path}" unless @options['silent']
101
+ exec { @client.delete_graph(path) }
56
102
  end
57
- complexes = @client.list_complex(base_path)
103
+ end
104
+
105
+ def delete_complexes(complexes, graph_names = nil)
58
106
  complexes.each do |graph|
59
- begin
60
- @client.delete_complex(graph['path'])
61
- $stdout.puts "Deleted #{graph['path']}" unless @options['silent']
62
- rescue => e
63
- puts "\tclass:#{e.class}\t#{e.message}"
64
- end
107
+ path = graph['path']
108
+ next if graph_names and !graph_names.include?(File.basename(path))
109
+ puts "Delete #{path}" unless @options['silent']
110
+ exec { @client.delete_complex(path) }
111
+ end
112
+ end
113
+
114
+ def setup_colors(colors, graphs)
115
+ graphs.each do |graph|
116
+ path = graph['path']
117
+ next unless color = colors[File.basename(path)]
118
+ data = { 'color' => color }
119
+ puts "Setup #{path} with #{color}" unless @options['silent']
120
+ exec { @client.edit_graph(path, data) }
121
+ end
122
+ end
123
+
124
+ def setup_complex(from_graphs, to_complex, graphs)
125
+ from_graph_first = from_graphs.first
126
+ graphs.each do |graph|
127
+ next unless File.basename(graph['path']) == from_graph_first
128
+ dirname = File.dirname(graph['path'])
129
+
130
+ base = {'gmode' => 'gauge', 'stack' => true, 'type' => 'AREA'}
131
+ from_graphs_params = from_graphs.map {|name| base.merge('path' => "#{dirname}/#{name}") }
132
+ to_complex_params = { 'path' => "#{dirname}/#{to_complex}", 'sort' => 0 }
133
+ puts "Setup #{dirname}/#{to_complex} with #{from_graphs}" unless @options['silent']
134
+ exec { @client.create_complex(from_graphs_params, to_complex_params) }
135
+ end
136
+ end
137
+
138
+ def exec(&blk)
139
+ begin
140
+ yield
141
+ rescue => e
142
+ $stderr.puts "\tclass:#{e.class}\t#{e.message}"
65
143
  end
66
- $stderr.puts "Not found" if graphs.empty? and complexes.empty? unless @options['silent']
67
144
  end
68
145
  end
69
146
 
@@ -15,7 +15,10 @@ module MultiForecast
15
15
  # @param [Hash] opts
16
16
  # [Hash] mapping: Mapping rules from `path` to GrowthForecast's `base_uri`.
17
17
  def initialize(opts = {})
18
- @mapping = opts['mapping'] || { '' => 'http://localhost:5125' }
18
+ @mapping = {}
19
+ mapping = opts['mapping'] || { '' => 'http://localhost:5125' }
20
+ # remove heading / of path
21
+ mapping.each {|key, val| @mapping[lstrip(key, '/')] = val }
19
22
  @short_metrics = opts['short_metrics'] || true
20
23
 
21
24
  @clients = {}
@@ -77,6 +80,7 @@ module MultiForecast
77
80
  end
78
81
 
79
82
  # Get the list of graphs, /json/list/graph
83
+ # @param [String] base_path
80
84
  # @return [Hash] list of graphs
81
85
  # @example
82
86
  # [
@@ -273,9 +277,10 @@ module MultiForecast
273
277
  # height [String] the height of image to show
274
278
  # @return [Hash] error response
275
279
  # @example
276
- def get_graph_uri(path, params = {})
277
- params = preprocess_time_params(params) if params
278
- "#{@base_uris[id(path)]}/graph/#{uri_escape(service_name(path))}/#{uri_escape(section_name(path))}/#{uri_escape(graph_name(path))}?#{query_string(params)}"
280
+ def get_graph_uri(path, params = nil)
281
+ params ||= {}
282
+ params = preprocess_time_params(params) unless params.empty?
283
+ "#{@base_uris[id(path)]}/graph/#{uri_escape(service_name(path))}/#{uri_escape(section_name(path))}/#{uri_escape(graph_name(path))}#{'?' unless params.empty?}#{query_string(params)}"
279
284
  end
280
285
 
281
286
  # Get complex graph image uri
@@ -291,9 +296,10 @@ module MultiForecast
291
296
  # height [String] the height of image to show
292
297
  # @return [Hash] error response
293
298
  # @example
294
- def get_complex_uri(path, params = {})
295
- params = preprocess_time_params(params) if params
296
- "#{@base_uris[id(path)]}/complex/graph/#{uri_escape(service_name(path))}/#{uri_escape(section_name(path))}/#{uri_escape(graph_name(path))}?#{query_string(params)}"
299
+ def get_complex_uri(path, params = nil)
300
+ params ||= {}
301
+ params = preprocess_time_params(params) unless params.empty?
302
+ "#{@base_uris[id(path)]}/complex/graph/#{uri_escape(service_name(path))}/#{uri_escape(section_name(path))}/#{uri_escape(graph_name(path))}#{'?' unless params.empty?}#{query_string(params)}"
297
303
  end
298
304
 
299
305
  # process the time params (from and to)
@@ -4,8 +4,10 @@ require 'cgi'
4
4
  module MultiForecast
5
5
  module ConversionRule
6
6
  def uri_escape(string)
7
- # + => '%20' is to avoid GF (Kossy?) bug
8
- # . => '%2E' because a/./b is recognized as a/b as URL
7
+ # Here, we want to do CGI.escape to encode '/', but GF (Plack?) does URI.unescape when it receives.
8
+ # Major Difference: In URI.escape, ' ' => '%20'. In CGI.escape, ' ' => '+'.
9
+ # Thus, we need to convert as ' ' => '+', and then, '+' => '%20' so that GF can unescape '%20' => ' '.
10
+ # '.' => '%2E' because a/./b is recognized as a/b as URL
9
11
  CGI.escape(string).gsub('+', '%20').gsub('.', '%2E') if string
10
12
  end
11
13
 
@@ -28,3 +28,7 @@ shared_examples_for 'graph_uri_params_fromto' do
28
28
  it { subject.should match(/(\?|&)from=#{Regexp.escape(URI.escape(params['from'].to_s))}(&|$)/) }
29
29
  it { subject.should match(/(\?|&)to=#{Regexp.escape(URI.escape(params['to'].to_s))}(&|$)/) }
30
30
  end
31
+
32
+ shared_examples_for 'graph_uri_empty_params' do
33
+ it { subject.should_not match(/(\?|&)/) }
34
+ end
@@ -6,9 +6,10 @@ Gem::Specification.new do |gem|
6
6
  gem.version = File.read(File.expand_path('VERSION', File.dirname(__FILE__))).chomp
7
7
  gem.authors = ["Naotoshi Seo"]
8
8
  gem.email = ["sonots@gmail.com"]
9
- gem.homepage = "https://github.com/sonots/multiforecast-client"
9
+ gem.homepage = "https://github.com/yohoushi/multiforecast-client"
10
10
  gem.summary = "Multiple GrowthForecast Client"
11
11
  gem.description = gem.summary
12
+ gem.licenses = ['MIT']
12
13
 
13
14
  gem.files = `git ls-files`.split($\)
14
15
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
@@ -8,6 +8,18 @@ describe MultiForecast::Client do
8
8
  complex_keys = %w[number complex created_at service_name section_name id graph_name data sumup
9
9
  description sort updated_at]
10
10
 
11
+ context "#initialize" do
12
+ context "typical" do
13
+ subject { MultiForecast::Client.new('mapping' => {'app1/' => 'http://localhost:5125'}) }
14
+ it { subject.instance_variable_get(:@mapping).keys.first.should == 'app1/' }
15
+ end
16
+
17
+ context "leading / of mapping path should be stripped" do
18
+ subject { MultiForecast::Client.new('mapping' => {'/app1/' => 'http://localhost:5125'}) }
19
+ it { subject.instance_variable_get(:@mapping).keys.first.should == 'app1/' }
20
+ end
21
+ end
22
+
11
23
  context "#list_graph" do
12
24
  include_context "stub_list_graph" if ENV['MOCK'] == 'on'
13
25
  subject { graphs }
@@ -86,7 +98,7 @@ describe MultiForecast::Client do
86
98
  end
87
99
  end
88
100
 
89
- describe "graph_uri" do
101
+ describe "graph_uri_term" do
90
102
  let(:params) do
91
103
  {
92
104
  't' => 'h',
@@ -104,6 +116,30 @@ describe MultiForecast::Client do
104
116
  end
105
117
  end
106
118
 
119
+ describe "graph_uri_empty" do
120
+ let(:params) { {} }
121
+ context "#get_graph_uri" do
122
+ subject { multiforecast.get_graph_uri(graph["path"], params) }
123
+ it_should_behave_like 'graph_uri_empty_params'
124
+ end
125
+ context "#get_complex_uri" do
126
+ subject { multiforecast.get_complex_uri(graph["path"], params) }
127
+ it_should_behave_like 'graph_uri_empty_params'
128
+ end
129
+ end
130
+
131
+ describe "graph_uri_nil" do
132
+ let(:params) { nil }
133
+ context "#get_graph_uri" do
134
+ subject { multiforecast.get_graph_uri(graph["path"], params) }
135
+ it_should_behave_like 'graph_uri_empty_params'
136
+ end
137
+ context "#get_complex_uri" do
138
+ subject { multiforecast.get_complex_uri(graph["path"], params) }
139
+ it_should_behave_like 'graph_uri_empty_params'
140
+ end
141
+ end
142
+
107
143
  describe "graph_uri_fromto" do
108
144
  shared_context "short_period" do
109
145
  before { now = Time.now; Time.stub(:now) { now } }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multiforecast-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.62.0.5
4
+ version: 0.62.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Naotoshi Seo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-26 00:00:00.000000000 Z
11
+ date: 2013-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: growthforecast-client
@@ -141,8 +141,9 @@ files:
141
141
  - spec/multiforecast/client_spec.rb
142
142
  - spec/multiforecast/conversion_rule_spec.rb
143
143
  - spec/spec_helper.rb
144
- homepage: https://github.com/sonots/multiforecast-client
145
- licenses: []
144
+ homepage: https://github.com/yohoushi/multiforecast-client
145
+ licenses:
146
+ - MIT
146
147
  metadata: {}
147
148
  post_install_message:
148
149
  rdoc_options: []
@@ -168,4 +169,3 @@ test_files:
168
169
  - spec/multiforecast/client_spec.rb
169
170
  - spec/multiforecast/conversion_rule_spec.rb
170
171
  - spec/spec_helper.rb
171
- has_rdoc: