doggy 2.1.1 → 3.0.0.pre.beta1
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/Gemfile.lock +3 -19
- data/README.md +0 -4
- data/dev.yml +1 -1
- data/doggy.gemspec +4 -10
- data/lib/doggy.rb +3 -5
- data/lib/doggy/cli.rb +0 -8
- data/lib/doggy/cli/delete.rb +0 -1
- data/lib/doggy/cli/edit.rb +6 -11
- data/lib/doggy/cli/mute.rb +0 -1
- data/lib/doggy/cli/pull.rb +29 -9
- data/lib/doggy/cli/push.rb +0 -1
- data/lib/doggy/cli/unmute.rb +0 -1
- data/lib/doggy/duration.rb +1 -1
- data/lib/doggy/hash_sort.rb +13 -0
- data/lib/doggy/model.rb +31 -40
- data/lib/doggy/models/dashboard.rb +44 -15
- data/lib/doggy/models/monitor.rb +44 -54
- metadata +5 -20
- data/lib/doggy/models/screen.rb +0 -52
- data/lib/doggy/version.rb +0 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: af6510f8934d8d58b5f5cf9a318c7c4fd66893651cc1fcf9c24db4ebfb46e56b
|
|
4
|
+
data.tar.gz: 264f30ed2bd2ea394a29cc780c266f5345c092dc485ea7eca742cf00d9f6505f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a7e116d5a61c47f44639695c245d3377c501a826935b33c39fa1b6d5ac487fef6f26ad6bc6395f572311d8101d129c544bac3366b08953fe48dbfeee897f551d
|
|
7
|
+
data.tar.gz: 55d8c1a9a3bb4797817d6ab012309e45a68855959c3bab9c47081e1ee85f354d0309dd1fbbbdfef2a7321fdbe9985bbd1eb020c4d4538945a10014b88e21f964
|
data/Gemfile.lock
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
doggy (
|
|
4
|
+
doggy (3.0.0.pre.beta1)
|
|
5
5
|
activesupport
|
|
6
6
|
parallel
|
|
7
7
|
rugged
|
|
8
8
|
thor
|
|
9
|
-
virtus
|
|
10
9
|
|
|
11
10
|
GEM
|
|
12
11
|
remote: https://rubygems.org/
|
|
@@ -19,23 +18,13 @@ GEM
|
|
|
19
18
|
addressable (2.6.0)
|
|
20
19
|
public_suffix (>= 2.0.2, < 4.0)
|
|
21
20
|
ast (2.4.0)
|
|
22
|
-
axiom-types (0.1.1)
|
|
23
|
-
descendants_tracker (~> 0.0.4)
|
|
24
|
-
ice_nine (~> 0.11.0)
|
|
25
|
-
thread_safe (~> 0.3, >= 0.3.1)
|
|
26
21
|
coderay (1.1.2)
|
|
27
|
-
coercible (1.0.0)
|
|
28
|
-
descendants_tracker (~> 0.0.1)
|
|
29
22
|
concurrent-ruby (1.1.5)
|
|
30
23
|
crack (0.4.3)
|
|
31
24
|
safe_yaml (~> 1.0.0)
|
|
32
|
-
|
|
33
|
-
thread_safe (~> 0.3, >= 0.3.1)
|
|
34
|
-
equalizer (0.0.11)
|
|
35
|
-
hashdiff (0.3.8)
|
|
25
|
+
hashdiff (0.3.9)
|
|
36
26
|
i18n (1.6.0)
|
|
37
27
|
concurrent-ruby (~> 1.0)
|
|
38
|
-
ice_nine (0.11.2)
|
|
39
28
|
jaro_winkler (1.5.2)
|
|
40
29
|
metaclass (0.0.4)
|
|
41
30
|
method_source (0.9.2)
|
|
@@ -43,7 +32,7 @@ GEM
|
|
|
43
32
|
mocha (1.8.0)
|
|
44
33
|
metaclass (~> 0.0.1)
|
|
45
34
|
parallel (1.17.0)
|
|
46
|
-
parser (2.6.
|
|
35
|
+
parser (2.6.3.0)
|
|
47
36
|
ast (~> 2.4.0)
|
|
48
37
|
pry (0.12.2)
|
|
49
38
|
coderay (~> 1.1.0)
|
|
@@ -68,11 +57,6 @@ GEM
|
|
|
68
57
|
tzinfo (1.2.5)
|
|
69
58
|
thread_safe (~> 0.1)
|
|
70
59
|
unicode-display_width (1.5.0)
|
|
71
|
-
virtus (1.0.5)
|
|
72
|
-
axiom-types (~> 0.1)
|
|
73
|
-
coercible (~> 1.0)
|
|
74
|
-
descendants_tracker (~> 0.0, >= 0.0.3)
|
|
75
|
-
equalizer (~> 0.0, >= 0.0.9)
|
|
76
60
|
webmock (3.5.1)
|
|
77
61
|
addressable (>= 2.3.6)
|
|
78
62
|
crack (>= 0.3.2)
|
data/README.md
CHANGED
|
@@ -30,10 +30,6 @@ Export `DATADOG_API_KEY` and `DATADOG_APP_KEY` environment variables and `doggy`
|
|
|
30
30
|
|
|
31
31
|
Optional: You can set `DATADOG_BASE_HUMAN_URL` environment variable if your organization uses a custom domain. This will change the urls given to users.
|
|
32
32
|
|
|
33
|
-
#### ejson
|
|
34
|
-
|
|
35
|
-
Set up `ejson` by putting `secrets.ejson` in your root object store.
|
|
36
|
-
|
|
37
33
|
#### json (plaintext)
|
|
38
34
|
|
|
39
35
|
If you're feeling adventurous, just put plaintext `secrets.json` in your root object store like this:
|
data/dev.yml
CHANGED
data/doggy.gemspec
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
|
-
lib = File.expand_path('../lib', __FILE__)
|
|
5
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
6
|
-
require 'doggy/version'
|
|
7
|
-
|
|
8
3
|
Gem::Specification.new do |spec|
|
|
9
4
|
spec.name = "doggy"
|
|
10
|
-
spec.version =
|
|
5
|
+
spec.version = "3.0.0-beta1"
|
|
11
6
|
spec.authors = ["Vlad Gorodetsky", "Andre Medeiros"]
|
|
12
7
|
spec.email = ["v@gor.io", "me@andremedeiros.info"]
|
|
13
8
|
|
|
@@ -25,13 +20,12 @@ Gem::Specification.new do |spec|
|
|
|
25
20
|
|
|
26
21
|
spec.add_runtime_dependency("parallel")
|
|
27
22
|
spec.add_runtime_dependency("thor")
|
|
28
|
-
spec.add_runtime_dependency("virtus")
|
|
29
23
|
spec.add_runtime_dependency("rugged")
|
|
30
|
-
spec.add_runtime_dependency(
|
|
24
|
+
spec.add_runtime_dependency("activesupport")
|
|
31
25
|
|
|
32
26
|
spec.add_development_dependency("bundler")
|
|
33
27
|
spec.add_development_dependency("rake")
|
|
34
28
|
spec.add_development_dependency("minitest")
|
|
35
|
-
spec.add_development_dependency(
|
|
36
|
-
spec.add_development_dependency(
|
|
29
|
+
spec.add_development_dependency("pry")
|
|
30
|
+
spec.add_development_dependency("rubocop")
|
|
37
31
|
end
|
data/lib/doggy.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
3
|
require "pathname"
|
|
5
4
|
require "net/http"
|
|
6
5
|
require "rugged"
|
|
7
6
|
|
|
7
|
+
require "doggy/hash_sort"
|
|
8
8
|
require "doggy/cli"
|
|
9
9
|
require "doggy/cli/edit"
|
|
10
10
|
require "doggy/cli/mute"
|
|
@@ -15,12 +15,10 @@ require "doggy/cli/delete"
|
|
|
15
15
|
require "doggy/model"
|
|
16
16
|
require "doggy/models/dashboard"
|
|
17
17
|
require "doggy/models/monitor"
|
|
18
|
-
require "doggy/models/screen"
|
|
19
|
-
require "doggy/version"
|
|
20
18
|
|
|
21
19
|
module Doggy
|
|
22
|
-
DOG_SKIP_REGEX =
|
|
23
|
-
MANAGED_BY_DOGGY_REGEX =
|
|
20
|
+
DOG_SKIP_REGEX = /😱|:scream:/i.freeze
|
|
21
|
+
MANAGED_BY_DOGGY_REGEX = /🐶|:dog:/i.freeze
|
|
24
22
|
|
|
25
23
|
class DoggyError < StandardError; end
|
|
26
24
|
|
data/lib/doggy/cli.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
3
|
require "thor"
|
|
@@ -7,13 +6,6 @@ module Doggy
|
|
|
7
6
|
class CLI < Thor
|
|
8
7
|
include Thor::Actions
|
|
9
8
|
|
|
10
|
-
map %w(--version -v) => :__print_version
|
|
11
|
-
|
|
12
|
-
desc '--version, -v', 'print the version'
|
|
13
|
-
def __print_version
|
|
14
|
-
puts Doggy::VERSION
|
|
15
|
-
end
|
|
16
|
-
|
|
17
9
|
desc "pull [IDs]", "Pulls objects from Datadog"
|
|
18
10
|
|
|
19
11
|
def pull(*ids)
|
data/lib/doggy/cli/delete.rb
CHANGED
data/lib/doggy/cli/edit.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
3
|
module Doggy
|
|
@@ -23,8 +22,6 @@ module Doggy
|
|
|
23
22
|
new_resource.description = resource.description
|
|
24
23
|
elsif new_resource.is_a?(Doggy::Models::Monitor)
|
|
25
24
|
new_resource.name = resource.name
|
|
26
|
-
elsif new_resource.is_a?(Doggy::Models::Screen)
|
|
27
|
-
new_resource.board_title = resource.board_title
|
|
28
25
|
end
|
|
29
26
|
new_resource.path = resource.path
|
|
30
27
|
new_resource.save_local
|
|
@@ -39,20 +36,18 @@ module Doggy
|
|
|
39
36
|
end
|
|
40
37
|
|
|
41
38
|
def fork(resource)
|
|
42
|
-
|
|
43
|
-
forked_resource = resource.
|
|
44
|
-
forked_resource.id = nil
|
|
39
|
+
forked_resource = resource.class.new(resource.attributes.except("id")) # TODO: Except "url" too
|
|
40
|
+
forked_resource.path = resource.path # TODO: should not be forked
|
|
45
41
|
forked_resource.refute_read_only!
|
|
42
|
+
|
|
46
43
|
if /dashboard/.match?(resource.class.to_s.downcase)
|
|
47
|
-
forked_resource.title = "[#{
|
|
48
|
-
forked_resource.description = "[fork of #{resource.id}] " + forked_resource.title
|
|
49
|
-
elsif /screen/.match?(resource.class.to_s.downcase)
|
|
50
|
-
forked_resource.board_title = "[#{salt}] " + forked_resource.board_title
|
|
44
|
+
forked_resource.title = "[#{Doggy.random_word}] #{resource.title}"
|
|
51
45
|
elsif /monitor/.match?(resource.class.to_s.downcase)
|
|
52
|
-
forked_resource.name = "[#{
|
|
46
|
+
forked_resource.name = "[#{Doggy.random_word}] #{resource.name}"
|
|
53
47
|
else
|
|
54
48
|
raise StandardError, 'Unknown resource type, cannot edit.'
|
|
55
49
|
end
|
|
50
|
+
|
|
56
51
|
forked_resource.save
|
|
57
52
|
forked_resource
|
|
58
53
|
end
|
data/lib/doggy/cli/mute.rb
CHANGED
data/lib/doggy/cli/pull.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
3
|
require 'parallel'
|
|
@@ -12,9 +11,20 @@ module Doggy
|
|
|
12
11
|
|
|
13
12
|
def run
|
|
14
13
|
@local_resources = Doggy::Model.all_local_resources
|
|
14
|
+
id_migration_mapping = {}
|
|
15
|
+
|
|
15
16
|
if @ids.empty?
|
|
16
17
|
Parallel.each(@local_resources) do |local_resource|
|
|
17
|
-
|
|
18
|
+
remote_resource = local_resource.class.find(local_resource.id)
|
|
19
|
+
if (new_id = remote_resource&.attributes&.dig("dash", "new_id")) || (new_id = remote_resource&.attributes&.dig("new_id"))
|
|
20
|
+
id_migration_mapping[local_resource.id.to_s] = local_resource.class.find(new_id)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if remote_resource
|
|
24
|
+
if id_migration_mapping.key?(local_resource.id)
|
|
25
|
+
remote_resource.attributes = id_migration_mapping[local_resource.id].attributes
|
|
26
|
+
end
|
|
27
|
+
|
|
18
28
|
remote_resource.path = local_resource.path
|
|
19
29
|
remote_resource.save_local
|
|
20
30
|
else
|
|
@@ -22,29 +32,34 @@ module Doggy
|
|
|
22
32
|
end
|
|
23
33
|
end
|
|
24
34
|
else
|
|
25
|
-
@ids.each { |id| pull_by_id(id.
|
|
35
|
+
@ids.each { |id| pull_by_id(id.to_s) }
|
|
26
36
|
end
|
|
27
37
|
end
|
|
28
38
|
|
|
29
39
|
private
|
|
30
40
|
|
|
31
41
|
def pull_by_id(id)
|
|
32
|
-
local_resources = @local_resources.find_all { |l| l.id == id }
|
|
42
|
+
local_resources = @local_resources.find_all { |l| l.id.to_s == id.to_s }
|
|
43
|
+
id_migration_mapping = {}
|
|
33
44
|
|
|
34
|
-
remote_resources = [Models::Dashboard, Models::Monitor
|
|
35
|
-
klass.find(id)
|
|
45
|
+
remote_resources = [Models::Dashboard, Models::Monitor].map do |klass|
|
|
46
|
+
result = klass.find(id.to_s)
|
|
47
|
+
if (new_id = result&.attributes&.dig("dash", "new_id")) || (new_id = result&.attributes&.dig("new_id"))
|
|
48
|
+
id_migration_mapping[id.to_s] = klass.find(new_id)
|
|
49
|
+
end
|
|
50
|
+
result
|
|
36
51
|
end.compact
|
|
37
52
|
|
|
38
53
|
if local_resources.size != remote_resources.size
|
|
39
|
-
normalized_remote_resources = remote_resources.map { |remote_resource| [remote_resource.class.name, remote_resource.id] }
|
|
40
|
-
normalized_local_resources = local_resources.map { |local_resource| [local_resource.class.name, local_resource.id] }
|
|
54
|
+
normalized_remote_resources = remote_resources.map { |remote_resource| [remote_resource.class.name, remote_resource.id.to_s] }
|
|
55
|
+
normalized_local_resources = local_resources.map { |local_resource| [local_resource.class.name, local_resource.id.to_s] }
|
|
41
56
|
normalized_resource_diff = Hash[normalized_remote_resources - normalized_local_resources]
|
|
42
57
|
|
|
43
58
|
# Here we traverse `remote_resources` to find remote resource with matching class name and id.
|
|
44
59
|
# We cannot subtract `local_resources` from `remote_resources` because those are different kind of objects.
|
|
45
60
|
remote_resources_to_be_saved = normalized_resource_diff.map do |klass, normalized_resource_id|
|
|
46
61
|
remote_resources.find do |rr|
|
|
47
|
-
rr.class.name == klass && rr.id == normalized_resource_id
|
|
62
|
+
rr.class.name == klass && rr.id.to_s == normalized_resource_id.to_s
|
|
48
63
|
end
|
|
49
64
|
end
|
|
50
65
|
|
|
@@ -52,6 +67,11 @@ module Doggy
|
|
|
52
67
|
else
|
|
53
68
|
local_resources.each do |local_resource|
|
|
54
69
|
remote_resource = local_resource.class.find(local_resource.id)
|
|
70
|
+
|
|
71
|
+
if id_migration_mapping.key?(local_resource.id)
|
|
72
|
+
remote_resource.attributes = id_migration_mapping[local_resource.id].attributes
|
|
73
|
+
end
|
|
74
|
+
|
|
55
75
|
remote_resource.path = local_resource.path
|
|
56
76
|
remote_resource.save_local
|
|
57
77
|
end
|
data/lib/doggy/cli/push.rb
CHANGED
data/lib/doggy/cli/unmute.rb
CHANGED
data/lib/doggy/duration.rb
CHANGED
|
@@ -23,7 +23,7 @@ module Duration
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
def self.parse(value)
|
|
26
|
-
unless match = DURATION_FORMAT.match(value)
|
|
26
|
+
unless (match = DURATION_FORMAT.match(value))
|
|
27
27
|
raise ArgumentError, "not a duration: #{value.inspect}, "\
|
|
28
28
|
"use digits followed by a unit (#{DURATION_UNITS.map { |k, v| "#{k} for #{v}" }.join(', ')})"
|
|
29
29
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class Hash
|
|
2
|
+
def sort_by_key(&block)
|
|
3
|
+
self.keys.sort(&block).reduce({}) do |seed, key|
|
|
4
|
+
seed[key] = self[key]
|
|
5
|
+
if seed[key].is_a?(Hash)
|
|
6
|
+
seed[key] = seed[key].sort_by_key(&block)
|
|
7
|
+
elsif seed[key].is_a?(Array)
|
|
8
|
+
seed[key] = seed[key].map { |i| i.sort_by_key(&block) }
|
|
9
|
+
end
|
|
10
|
+
seed
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
data/lib/doggy/model.rb
CHANGED
|
@@ -1,30 +1,32 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
3
|
require "json"
|
|
5
4
|
require "parallel"
|
|
6
5
|
require "uri"
|
|
7
|
-
require "
|
|
6
|
+
require "active_support/core_ext/hash/keys"
|
|
8
7
|
|
|
9
8
|
module Doggy
|
|
10
9
|
class Model
|
|
11
|
-
|
|
10
|
+
# Denormalized object attributes.
|
|
11
|
+
attr_accessor :attributes
|
|
12
12
|
|
|
13
13
|
# This stores the path on disk. We don't define it as a model attribute so
|
|
14
14
|
# it doesn't get serialized.
|
|
15
15
|
attr_accessor :path
|
|
16
16
|
|
|
17
|
-
#
|
|
17
|
+
# Indicates whether an object locally deleted
|
|
18
18
|
attr_accessor :is_deleted
|
|
19
19
|
|
|
20
20
|
# This stores whether the resource has been loaded locally or remotely.
|
|
21
21
|
attr_accessor :loading_source
|
|
22
22
|
|
|
23
23
|
class << self
|
|
24
|
-
attr_accessor :root
|
|
25
|
-
|
|
26
24
|
def find(id)
|
|
27
|
-
attributes = request(:get, resource_url(id), nil, [404])
|
|
25
|
+
attributes = request(:get, resource_url(id), nil, [404, 400])
|
|
26
|
+
if self == Doggy::Models::Dashboard
|
|
27
|
+
attributes = request(:get, resource_url(id, "dash"), nil, [404, 400]) if attributes['errors']
|
|
28
|
+
attributes = request(:get, resource_url(id, "screen"), nil, [404, 400]) if attributes['errors']
|
|
29
|
+
end
|
|
28
30
|
return if attributes['errors']
|
|
29
31
|
resource = new(attributes)
|
|
30
32
|
|
|
@@ -34,11 +36,13 @@ module Doggy
|
|
|
34
36
|
|
|
35
37
|
def find_local(param)
|
|
36
38
|
resources = Doggy::Model.all_local_resources
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
param = param.to_s
|
|
40
|
+
if (param =~ /^[0-9]+$/) || (param =~ /^[a-z0-9]+-[a-z0-9]+-[a-z0-9]+$/)
|
|
41
|
+
id = param
|
|
42
|
+
return resources.find { |res| res.id == id.to_s || res.id == id.to_i }
|
|
39
43
|
end
|
|
40
|
-
if id = param[%r{(
|
|
41
|
-
return resources.find { |res| res.id ==
|
|
44
|
+
if (id = param[%r{(dashboard/|monitors#)(\d+)}i, 2])
|
|
45
|
+
return resources.find { |res| res.id == id.to_s || res.id == id.to_i }
|
|
42
46
|
end
|
|
43
47
|
full_path = File.expand_path(param.gsub('objects/', ''), Doggy.object_root)
|
|
44
48
|
resources.find { |res| res.path == full_path }
|
|
@@ -84,10 +88,7 @@ module Doggy
|
|
|
84
88
|
end
|
|
85
89
|
|
|
86
90
|
def infer_type(attributes)
|
|
87
|
-
|
|
88
|
-
return Models::Dashboard if has_key.call('graphs')
|
|
89
|
-
return Models::Monitor if has_key.call('message')
|
|
90
|
-
return Models::Screen if has_key.call('board_title')
|
|
91
|
+
attributes.key?("message") ? Models::Monitor : Models::Dashboard
|
|
91
92
|
end
|
|
92
93
|
|
|
93
94
|
def request(method, url, body = nil, accepted_errors = nil)
|
|
@@ -103,11 +104,11 @@ module Doggy
|
|
|
103
104
|
http.use_ssl = (uri.scheme == 'https')
|
|
104
105
|
|
|
105
106
|
request = case method
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
when :get then Net::HTTP::Get.new(uri.request_uri)
|
|
108
|
+
when :post then Net::HTTP::Post.new(uri.request_uri)
|
|
109
|
+
when :put then Net::HTTP::Put.new(uri.request_uri)
|
|
110
|
+
when :delete then Net::HTTP::Delete.new(uri.request_uri)
|
|
111
|
+
end
|
|
111
112
|
|
|
112
113
|
request.content_type = 'application/json'
|
|
113
114
|
request.body = body if body
|
|
@@ -149,15 +150,8 @@ module Doggy
|
|
|
149
150
|
}.to_json)
|
|
150
151
|
end
|
|
151
152
|
|
|
152
|
-
def sort_by_key(hash
|
|
153
|
-
hash
|
|
154
|
-
seed[key] = hash[key]
|
|
155
|
-
if seed[key].is_a?(Hash)
|
|
156
|
-
seed[key] = Doggy::Model.sort_by_key(seed[key], &block)
|
|
157
|
-
elsif seed[key].is_a?(Array)
|
|
158
|
-
seed[key].each_with_index { |e, i| seed[key][i] = sort_by_key(e, &block) if e.is_a?(Hash) }
|
|
159
|
-
end
|
|
160
|
-
end
|
|
153
|
+
def sort_by_key(hash)
|
|
154
|
+
hash
|
|
161
155
|
end
|
|
162
156
|
|
|
163
157
|
protected
|
|
@@ -167,18 +161,15 @@ module Doggy
|
|
|
167
161
|
end
|
|
168
162
|
end # class << self
|
|
169
163
|
|
|
170
|
-
def ==(
|
|
171
|
-
to_h ==
|
|
164
|
+
def ==(other)
|
|
165
|
+
to_h == other.to_h
|
|
172
166
|
end
|
|
173
167
|
|
|
174
|
-
def initialize(attributes =
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
return super unless attributes && root_key
|
|
178
|
-
return super unless attributes[root_key].is_a?(Hash)
|
|
168
|
+
def initialize(attributes = {})
|
|
169
|
+
@attributes = attributes.deep_stringify_keys
|
|
179
170
|
|
|
180
|
-
attributes = attributes[
|
|
181
|
-
|
|
171
|
+
@attributes["id"] = @attributes["id"].to_s if @attributes["id"]
|
|
172
|
+
@attributes["options"] ||= {} if self.class == Doggy::Models::Monitor
|
|
182
173
|
end
|
|
183
174
|
|
|
184
175
|
def save_local
|
|
@@ -188,7 +179,7 @@ module Doggy
|
|
|
188
179
|
end
|
|
189
180
|
|
|
190
181
|
def to_h
|
|
191
|
-
Doggy::Model.sort_by_key(
|
|
182
|
+
Doggy::Model.sort_by_key(attributes)
|
|
192
183
|
end
|
|
193
184
|
|
|
194
185
|
def validate
|
|
@@ -212,7 +203,7 @@ module Doggy
|
|
|
212
203
|
end
|
|
213
204
|
|
|
214
205
|
def destroy
|
|
215
|
-
self.class.request(:delete, resource_url(id), nil, [404])
|
|
206
|
+
self.class.request(:delete, resource_url(id), nil, [404, 400])
|
|
216
207
|
end
|
|
217
208
|
|
|
218
209
|
def destroy_local
|
|
@@ -1,21 +1,50 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
3
|
module Doggy
|
|
5
4
|
module Models
|
|
6
5
|
class Dashboard < Doggy::Model
|
|
7
|
-
|
|
6
|
+
def id
|
|
7
|
+
attributes["id"]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def id=(v)
|
|
11
|
+
attributes["id"] = v
|
|
12
|
+
end
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
def title
|
|
15
|
+
attributes["title"]
|
|
16
|
+
end
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
def title=(v)
|
|
19
|
+
attributes["title"] = v
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def description
|
|
23
|
+
attributes["description"]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def description=(v)
|
|
27
|
+
attributes["description"] = v
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def read_only
|
|
31
|
+
if attributes["widgets"]
|
|
32
|
+
attributes["is_read_only"]
|
|
33
|
+
else
|
|
34
|
+
attributes["read_only"]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def read_only=(v)
|
|
39
|
+
if attributes["widgets"]
|
|
40
|
+
attributes["is_read_only"] = v
|
|
41
|
+
else
|
|
42
|
+
attributes["read_only"] = v
|
|
43
|
+
end
|
|
44
|
+
end
|
|
16
45
|
|
|
17
46
|
def prefix
|
|
18
|
-
'
|
|
47
|
+
'dashboard'
|
|
19
48
|
end
|
|
20
49
|
|
|
21
50
|
def ensure_read_only!
|
|
@@ -26,22 +55,22 @@ module Doggy
|
|
|
26
55
|
self.read_only = false
|
|
27
56
|
end
|
|
28
57
|
|
|
29
|
-
def self.resource_url(id = nil)
|
|
30
|
-
["https://app.datadoghq.com/api/v1
|
|
58
|
+
def self.resource_url(id = nil, kind = "dashboard")
|
|
59
|
+
["https://app.datadoghq.com/api/v1/#{kind}", id].compact.join("/")
|
|
31
60
|
end
|
|
32
61
|
|
|
33
62
|
def managed?
|
|
34
|
-
|
|
63
|
+
title !~ Doggy::DOG_SKIP_REGEX
|
|
35
64
|
end
|
|
36
65
|
|
|
37
66
|
def ensure_managed_emoji!
|
|
38
67
|
return unless managed?
|
|
39
|
-
return if title =~
|
|
40
|
-
self.title
|
|
68
|
+
return if title =~ /🐶/
|
|
69
|
+
self.title = "#{title} 🐶"
|
|
41
70
|
end
|
|
42
71
|
|
|
43
72
|
def human_url
|
|
44
|
-
"https://#{Doggy.base_human_url}/
|
|
73
|
+
"https://#{Doggy.base_human_url}/dashboard/#{id}"
|
|
45
74
|
end
|
|
46
75
|
|
|
47
76
|
# Dashboards don't have a direct edit URL
|
data/lib/doggy/models/monitor.rb
CHANGED
|
@@ -1,70 +1,64 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
3
|
module Doggy
|
|
5
4
|
module Models
|
|
6
5
|
class Monitor < Doggy::Model
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
6
|
+
def id
|
|
7
|
+
attributes["id"]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def id=(v)
|
|
11
|
+
attributes["id"] = v
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def name
|
|
15
|
+
attributes["name"]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def name=(v)
|
|
19
|
+
attributes["name"] = v
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def locked
|
|
23
|
+
attributes["options"]["locked"]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def locked=(v)
|
|
27
|
+
attributes["options"]["locked"] = v
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def silenced
|
|
31
|
+
attributes["options"]["silenced"]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def silenced=(v)
|
|
35
|
+
attributes["options"]["silenced"] = v
|
|
36
|
+
end
|
|
35
37
|
|
|
36
38
|
def prefix
|
|
37
39
|
'monitor'
|
|
38
40
|
end
|
|
39
41
|
|
|
40
42
|
def ensure_read_only!
|
|
41
|
-
|
|
42
|
-
options.locked = true
|
|
43
|
-
else
|
|
44
|
-
self.options = Options.new(locked: true)
|
|
45
|
-
end
|
|
43
|
+
attributes["options"]["locked"] = true
|
|
46
44
|
end
|
|
47
45
|
|
|
48
46
|
def refute_read_only!
|
|
49
|
-
|
|
50
|
-
options.locked = false
|
|
51
|
-
else
|
|
52
|
-
self.options = Options.new(locked: false)
|
|
53
|
-
end
|
|
47
|
+
attributes["options"]["locked"] = false
|
|
54
48
|
end
|
|
55
49
|
|
|
56
|
-
def self.resource_url(id = nil)
|
|
57
|
-
["https://app.datadoghq.com/api/v1
|
|
50
|
+
def self.resource_url(id = nil, kind = "monitor")
|
|
51
|
+
["https://app.datadoghq.com/api/v1/#{kind}", id].compact.join("/")
|
|
58
52
|
end
|
|
59
53
|
|
|
60
54
|
def managed?
|
|
61
|
-
|
|
55
|
+
name !~ Doggy::DOG_SKIP_REGEX
|
|
62
56
|
end
|
|
63
57
|
|
|
64
58
|
def ensure_managed_emoji!
|
|
65
59
|
return unless managed?
|
|
66
|
-
return if name =~
|
|
67
|
-
self.name += "
|
|
60
|
+
return if name =~ /🐶/
|
|
61
|
+
self.name += " 🐶"
|
|
68
62
|
end
|
|
69
63
|
|
|
70
64
|
def validate
|
|
@@ -74,11 +68,11 @@ module Doggy
|
|
|
74
68
|
def toggle_mute!(action, body = nil)
|
|
75
69
|
return unless %w[mute unmute].include?(action) && id
|
|
76
70
|
attributes = request(:post, "#{resource_url(id)}/#{action}", body)
|
|
77
|
-
if message = attributes['errors']
|
|
71
|
+
if (message = attributes['errors'])
|
|
78
72
|
Doggy.ui.error(message)
|
|
79
73
|
else
|
|
80
74
|
self.attributes = attributes
|
|
81
|
-
if local_version = Doggy::Model.find_local(id)
|
|
75
|
+
if (local_version = Doggy::Model.find_local(id))
|
|
82
76
|
self.path = local_version.path
|
|
83
77
|
end
|
|
84
78
|
save_local
|
|
@@ -93,19 +87,15 @@ module Doggy
|
|
|
93
87
|
"https://#{Doggy.base_human_url}/monitors##{id}/edit"
|
|
94
88
|
end
|
|
95
89
|
|
|
96
|
-
def to_h
|
|
97
|
-
Doggy::Model.sort_by_key(super.merge(options: options.to_h))
|
|
98
|
-
end
|
|
99
|
-
|
|
100
90
|
private
|
|
101
91
|
|
|
102
92
|
def ensure_renotify_interval_valid
|
|
103
|
-
return unless options
|
|
93
|
+
return unless attributes.dig("options", "renotify_interval") && attributes.dig("options", "renotify_interval").to_i > 0
|
|
104
94
|
|
|
105
95
|
allowed_renotify_intervals = [10, 20, 30, 40, 50, 60, 90, 120, 180, 240, 300, 360, 720, 1440] # minutes
|
|
106
|
-
best_matching_interval = allowed_renotify_intervals.min_by { |x| (x.to_f - options
|
|
107
|
-
puts "WARN: Monitor #{id} uses invalid escalation interval (renotify_interval) #{options
|
|
108
|
-
options
|
|
96
|
+
best_matching_interval = allowed_renotify_intervals.min_by { |x| (x.to_f - attributes["options"]["renotify_interval"]).abs }
|
|
97
|
+
puts "WARN: Monitor #{id} uses invalid escalation interval (renotify_interval) #{attributes["options"]["renotify_interval"]}, using #{best_matching_interval} instead"
|
|
98
|
+
attributes["options"]["renotify_interval"] = best_matching_interval
|
|
109
99
|
end
|
|
110
100
|
end # Monitor
|
|
111
101
|
end # Models
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: doggy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.0.0.pre.beta1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vlad Gorodetsky
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: exe
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2019-
|
|
12
|
+
date: 2019-05-08 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: parallel
|
|
@@ -39,20 +39,6 @@ dependencies:
|
|
|
39
39
|
- - ">="
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
41
|
version: '0'
|
|
42
|
-
- !ruby/object:Gem::Dependency
|
|
43
|
-
name: virtus
|
|
44
|
-
requirement: !ruby/object:Gem::Requirement
|
|
45
|
-
requirements:
|
|
46
|
-
- - ">="
|
|
47
|
-
- !ruby/object:Gem::Version
|
|
48
|
-
version: '0'
|
|
49
|
-
type: :runtime
|
|
50
|
-
prerelease: false
|
|
51
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
52
|
-
requirements:
|
|
53
|
-
- - ">="
|
|
54
|
-
- !ruby/object:Gem::Version
|
|
55
|
-
version: '0'
|
|
56
42
|
- !ruby/object:Gem::Dependency
|
|
57
43
|
name: rugged
|
|
58
44
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -184,11 +170,10 @@ files:
|
|
|
184
170
|
- lib/doggy/cli/push.rb
|
|
185
171
|
- lib/doggy/cli/unmute.rb
|
|
186
172
|
- lib/doggy/duration.rb
|
|
173
|
+
- lib/doggy/hash_sort.rb
|
|
187
174
|
- lib/doggy/model.rb
|
|
188
175
|
- lib/doggy/models/dashboard.rb
|
|
189
176
|
- lib/doggy/models/monitor.rb
|
|
190
|
-
- lib/doggy/models/screen.rb
|
|
191
|
-
- lib/doggy/version.rb
|
|
192
177
|
homepage: http://github.com/shopify/doggy
|
|
193
178
|
licenses:
|
|
194
179
|
- MIT
|
|
@@ -204,9 +189,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
204
189
|
version: '2.5'
|
|
205
190
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
206
191
|
requirements:
|
|
207
|
-
- - "
|
|
192
|
+
- - ">"
|
|
208
193
|
- !ruby/object:Gem::Version
|
|
209
|
-
version:
|
|
194
|
+
version: 1.3.1
|
|
210
195
|
requirements: []
|
|
211
196
|
rubyforge_project:
|
|
212
197
|
rubygems_version: 2.7.6
|
data/lib/doggy/models/screen.rb
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
module Doggy
|
|
5
|
-
module Models
|
|
6
|
-
class Screen < Doggy::Model
|
|
7
|
-
attribute :id, Integer
|
|
8
|
-
attribute :board_title, String
|
|
9
|
-
|
|
10
|
-
attribute :board_bgtype, String
|
|
11
|
-
attribute :templated, Boolean
|
|
12
|
-
attribute :template_variables, Array[Hash]
|
|
13
|
-
attribute :widgets, Array[Hash]
|
|
14
|
-
attribute :height, String
|
|
15
|
-
attribute :width, String
|
|
16
|
-
attribute :read_only, Boolean
|
|
17
|
-
|
|
18
|
-
def prefix
|
|
19
|
-
'screen'
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def ensure_read_only!
|
|
23
|
-
self.read_only = true
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def refute_read_only!
|
|
27
|
-
self.read_only = false
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def self.resource_url(id = nil)
|
|
31
|
-
["https://app.datadoghq.com/api/v1/screen", id].compact.join("/")
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def managed?
|
|
35
|
-
!(board_title =~ Doggy::DOG_SKIP_REGEX)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def ensure_managed_emoji!
|
|
39
|
-
return unless managed?
|
|
40
|
-
return if board_title =~ /\xF0\x9F\x90\xB6/
|
|
41
|
-
self.board_title += " \xF0\x9F\x90\xB6"
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def human_url
|
|
45
|
-
"https://#{Doggy.base_human_url}/screen/#{id}"
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Screens don't have a direct edit URL
|
|
49
|
-
alias_method :human_edit_url, :human_url
|
|
50
|
-
end # Screen
|
|
51
|
-
end # Models
|
|
52
|
-
end # Doggy
|