hu 0.1.0 → 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.
- checksums.yaml +4 -4
- data/lib/hu/collab.rb +106 -28
- data/lib/hu/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ba8da38f5fc39bc25815bdf69477b5edad4d874
|
4
|
+
data.tar.gz: ef624c9fdb0a9887f200b4f7f571644368031172
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 808970b25fabe8daed670c50b98c4b238d424799c2ce99d03f00d7b097545343ed46aa7a9ae42a963900a82051c2d309c5fda7e6dabc643be4865e380507a6fe
|
7
|
+
data.tar.gz: 7f83bded558c4c14a64bea83f2da64987d15691bcb16346e4bfa2aaa96bfdceb210919b21de80d1fd5f5d9250e85f81974f50825f149054bf51a93a01ae5c39b
|
data/lib/hu/collab.rb
CHANGED
@@ -1,18 +1,33 @@
|
|
1
1
|
require 'powerbar'
|
2
2
|
require 'yaml'
|
3
3
|
require 'hashdiff'
|
4
|
+
require 'set'
|
4
5
|
require 'platform-api'
|
5
6
|
|
6
7
|
module Hu
|
7
8
|
class Cli < Optix::Cli
|
8
9
|
class Collab < Optix::Cli
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
text "Manage application/collaborator mapping."
|
12
|
+
text ""
|
13
|
+
text "Start by exporting the current mapping,"
|
14
|
+
text "edit to taste, then diff and import."
|
15
|
+
text ""
|
16
|
+
text "WARNING: If you remove yourself from an application"
|
17
|
+
text " then hu won't be able to see it anymore."
|
18
|
+
text ""
|
19
|
+
text "Please note that hu can only operate on applications and"
|
20
|
+
text "collaborators that it sees. It will stubbornly refuse to"
|
21
|
+
text "create new applications or collaborators."
|
22
|
+
text ""
|
23
|
+
text "Follow this procedure to introduce a new collaborator:"
|
24
|
+
text ""
|
25
|
+
text "1. Create collaborator on heroku (via web or toolbelt)"
|
26
|
+
text "2. Add them to at least one application that you have access to"
|
27
|
+
text ""
|
28
|
+
text "Now the new collaborator will show up in 'export'"
|
29
|
+
text "and may be assigned to applications."
|
30
|
+
def collab; end
|
16
31
|
|
17
32
|
OP_COLORS = {
|
18
33
|
'+' => "\e[0;1;32m",
|
@@ -20,17 +35,56 @@ module Hu
|
|
20
35
|
'~' => "\e[0;32m",
|
21
36
|
}
|
22
37
|
desc "Read mapping from stdin and diff to heroku state"
|
38
|
+
text "Read mapping from stdin and diff to heroku state"
|
23
39
|
parent "collab"
|
24
40
|
def diff(cmd, opts, argv)
|
25
41
|
parsed_state = parse_as_json_or_yaml(STDIN.read)
|
26
|
-
plan(HashDiff.diff(heroku_state, parsed_state)).each do |s|
|
42
|
+
plan(HashDiff.diff(heroku_state['apps'], parsed_state['apps'])).each do |s|
|
27
43
|
color = OP_COLORS[s[:op]]
|
28
44
|
msg = ''
|
29
45
|
if s[:method].nil?
|
30
46
|
color = "\e[0;41;33;1m"
|
31
47
|
msg = "Can not resolve this."
|
32
48
|
end
|
33
|
-
printf "%s%6s %-30s %-15s %-30s %s\e[0m\n", color, s[:op_name], s[:app_name], s[:role], s[:value], msg
|
49
|
+
STDERR.printf "%s%6s %-30s %-15s %-30s %s\e[0m\n", color, s[:op_name], s[:app_name], s[:role], s[:value], msg
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "Print current mapping to stdout"
|
54
|
+
text "Print current mapping to stdout"
|
55
|
+
opt :format, "yaml|json", :default => 'yaml'
|
56
|
+
parent "collab", "Application collaborators"
|
57
|
+
def export(cmd, opts, argv)
|
58
|
+
puts heroku_state.send("to_#{opts[:format]}".to_sym)
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "Read mapping from stdin and push to heroku"
|
62
|
+
text "Read mapping from stdin and push to heroku"
|
63
|
+
parent "collab"
|
64
|
+
def import(cmd, opts, argv)
|
65
|
+
parsed_state = parse_as_json_or_yaml(STDIN.read)
|
66
|
+
plan(HashDiff.diff(heroku_state['apps'], parsed_state['apps'])).each do |s|
|
67
|
+
color = OP_COLORS[s[:op]]
|
68
|
+
msg = ''
|
69
|
+
icon = ' '
|
70
|
+
eol = "\e[100D"
|
71
|
+
if s[:method].nil?
|
72
|
+
color = "\e[0;41;33;1m"
|
73
|
+
msg = "Skipped."
|
74
|
+
icon = "\e[0;31;1m\u2718\e[0m" # X
|
75
|
+
eol = "\n"
|
76
|
+
end
|
77
|
+
STDERR.printf "%s %s%6s %-30s %-15s %-30s %s\e[0m%s", icon, color, s[:op_name], s[:app_name], s[:role], s[:value], msg, eol
|
78
|
+
next if s[:method].nil?
|
79
|
+
begin
|
80
|
+
self.send(s[:method], s)
|
81
|
+
STDERR.puts "\e[0;32;1m\u2713\e[0m\n" # check
|
82
|
+
rescue => e
|
83
|
+
STDERR.puts "\e[0;31;1m\u2718\e[0m\n" # X
|
84
|
+
puts e.inspect
|
85
|
+
puts e.backtrace
|
86
|
+
exit 1
|
87
|
+
end
|
34
88
|
end
|
35
89
|
end
|
36
90
|
|
@@ -41,9 +95,11 @@ module Hu
|
|
41
95
|
}
|
42
96
|
def plan(diff)
|
43
97
|
plan = []
|
44
|
-
diff.each do |op, target,
|
98
|
+
diff.each do |op, target, lval, rval|
|
99
|
+
value = rval || lval
|
45
100
|
app_name, role = target.split('.')
|
46
|
-
|
101
|
+
|
102
|
+
role = role.split('[')[0] unless role.nil?
|
47
103
|
op_name = OP_MAP[op]
|
48
104
|
method_name = "op_#{op_name}_#{role}".to_sym
|
49
105
|
plan << {
|
@@ -58,12 +114,12 @@ module Hu
|
|
58
114
|
plan
|
59
115
|
end
|
60
116
|
|
61
|
-
def op_add_collaborators(
|
62
|
-
|
117
|
+
def op_add_collaborators(args)
|
118
|
+
h.collaborator.create(args[:app_name], :user => args[:value])
|
63
119
|
end
|
64
120
|
|
65
|
-
def op_remove_collaborators(
|
66
|
-
|
121
|
+
def op_remove_collaborators(args)
|
122
|
+
h.collaborator.delete(args[:app_name], args[:value])
|
67
123
|
end
|
68
124
|
|
69
125
|
def parse_as_json_or_yaml(input)
|
@@ -84,28 +140,50 @@ module Hu
|
|
84
140
|
raise ArgumentError
|
85
141
|
end
|
86
142
|
end
|
143
|
+
normalize(parsed)
|
144
|
+
end
|
145
|
+
|
146
|
+
def normalize(parsed)
|
147
|
+
unless parsed.include? 'apps'
|
148
|
+
raise ArgumentError, "Malformed input, key 'apps' not found."
|
149
|
+
end
|
150
|
+
parsed['apps'].each do |app_name, v|
|
151
|
+
unless heroku_state['apps'].include? app_name
|
152
|
+
raise ArgumentError, "Unknown application: #{app_name}"
|
153
|
+
end
|
154
|
+
next unless v['collaborators'].is_a? Array
|
155
|
+
v['collaborators'].flatten!.sort!.each do |collab|
|
156
|
+
unless heroku_state['collaborators'].include? collab
|
157
|
+
raise ArgumentError, "Unknown collaborator: #{collab}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
87
161
|
parsed
|
88
162
|
end
|
89
163
|
|
90
|
-
def heroku_state
|
91
|
-
|
164
|
+
def heroku_state(force_refresh=false)
|
165
|
+
return @heroku_state unless force_refresh or @heroku_state.nil?
|
166
|
+
all_collaborators = Set.new
|
167
|
+
data = { 'apps' => {} }
|
92
168
|
app_names = h.app.list.map{|e| e['name']}
|
93
169
|
app_names.each_with_index do |app_name,i|
|
94
170
|
pb :msg => app_name, :total => app_names.length, :done => i+1
|
95
|
-
data[app_name] = { 'collaborators' => [] }
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
171
|
+
d = data['apps'][app_name] = { 'collaborators' => [] }
|
172
|
+
h.collaborator.list(app_name).map{|e|
|
173
|
+
case e['role']
|
174
|
+
when 'owner'
|
175
|
+
d['owner'] = e['user']['email']
|
176
|
+
when nil
|
177
|
+
d['collaborators'] << e['user']['email']
|
178
|
+
else
|
179
|
+
raise RuntimeError, "Unknown collaborator role: #{e['role']}"
|
180
|
+
end
|
181
|
+
all_collaborators << e['user']['email']
|
182
|
+
}
|
106
183
|
end
|
107
184
|
pb :wipe
|
108
|
-
data
|
185
|
+
data['collaborators'] = all_collaborators.to_a.sort
|
186
|
+
@heroku_state = data
|
109
187
|
end
|
110
188
|
|
111
189
|
def h
|
data/lib/hu/version.rb
CHANGED