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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hu/collab.rb +106 -28
  3. data/lib/hu/version.rb +1 -1
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 135742548802f1cf65c42791d2c27839da18c4d6
4
- data.tar.gz: 5873b031208439a1f552d4a1bdedf8864d592b96
3
+ metadata.gz: 8ba8da38f5fc39bc25815bdf69477b5edad4d874
4
+ data.tar.gz: ef624c9fdb0a9887f200b4f7f571644368031172
5
5
  SHA512:
6
- metadata.gz: 362abd3e5beed4cb0ffbfb96610be2663c2afe689ff858417375cf6f06d15e436902a4156faf994820093f16be30cb959d0cbfe39ef4d523c4c8edeba7e0d136
7
- data.tar.gz: e2b6081abd344ee8f36a2b06bd1095d1594dfb7b675631bdc9ecc78c58849b0e9b41774433fc0897f9b48e56fdcd6dec22aca28ed014b35ae81dd94edfc04b95
6
+ metadata.gz: 808970b25fabe8daed670c50b98c4b238d424799c2ce99d03f00d7b097545343ed46aa7a9ae42a963900a82051c2d309c5fda7e6dabc643be4865e380507a6fe
7
+ data.tar.gz: 7f83bded558c4c14a64bea83f2da64987d15691bcb16346e4bfa2aaa96bfdceb210919b21de80d1fd5f5d9250e85f81974f50825f149054bf51a93a01ae5c39b
@@ -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
- desc "Print current mapping to stdout"
11
- opt :format, "yaml|json", :default => 'yaml'
12
- parent "collab", "Application collaborators"
13
- def export(cmd, opts, argv)
14
- puts heroku_state.send("to_#{opts[:format]}".to_sym)
15
- end
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, value|
98
+ diff.each do |op, target, lval, rval|
99
+ value = rval || lval
45
100
  app_name, role = target.split('.')
46
- role = role.split('[')[0]
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(name)
62
- raise NotImplementedError
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(name)
66
- raise NotImplementedError
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
- data = {}
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
- h.collaborator.list(app_name).map{|e|
97
- case e['role']
98
- when 'owner'
99
- data[app_name]['owner'] = e['user']['email']
100
- when nil
101
- data[app_name]['collaborators'] << e['user']['email']
102
- else
103
- raise RuntimeError, "Unknown collaborator role: #{e['role']}"
104
- end
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
@@ -1,3 +1,3 @@
1
1
  module Hu
2
- VERSION = "0.1.0"
2
+ VERSION = "1.0.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - moe