multiforecast-client 0.62.0.5 → 0.62.0.8
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 +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +25 -1
- data/README.md +13 -1
- data/VERSION +1 -1
- data/lib/multiforecast/cli.rb +96 -19
- data/lib/multiforecast/client.rb +13 -7
- data/lib/multiforecast/conversion_rule.rb +4 -2
- data/lib/multiforecast/shared_examples.rb +4 -0
- data/multiforecast-client.gemspec +2 -1
- data/spec/multiforecast/client_spec.rb +37 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0b9877d259aaf94156087bbac8bb9aa66694db1c
|
4
|
+
data.tar.gz: 187c70b320517e6df23d68877d9bd881b5f55c08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddc753bd90d278f704fc8aa87ee2e04fe4ce8e1b9aed7d11a21ed94912f17a47df6c98a7999d314261015d84d02f11cda1977341e760d866d8920c8e3ee036ca
|
7
|
+
data.tar.gz: 0cce09b837eb7a5cd5a1a04dbca59fe69a7cecd58da04d45129e202bca6c5d3cd0f3644fc4e1e315ceb84280697da59013b40f76b1c2b152200f1ec76d9b9e09
|
data/.gitignore
CHANGED
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
|
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.
|
1
|
+
0.62.0.8
|
data/lib/multiforecast/cli.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
103
|
+
end
|
104
|
+
|
105
|
+
def delete_complexes(complexes, graph_names = nil)
|
58
106
|
complexes.each do |graph|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
|
data/lib/multiforecast/client.rb
CHANGED
@@ -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 =
|
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
|
278
|
-
|
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
|
296
|
-
|
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
|
-
#
|
8
|
-
# . => '%
|
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/
|
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 "
|
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.
|
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-
|
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/
|
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:
|