hu 1.0.5 → 1.1.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 +77 -47
  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: fbd2e52b178103d9d0471786766bc5b18143e5a1
4
- data.tar.gz: e08bc81f41a5daeb9c5be749961ec6bc2dbb87e3
3
+ metadata.gz: 003507bbb3db74b361b601858c57fcd190ab5ba9
4
+ data.tar.gz: dd11b4e74533f76d52deeb4149c1a3dce3a25b28
5
5
  SHA512:
6
- metadata.gz: d4dd745b5ed60c26bb57de481a835147538f4131b8aa465e5fa7f059085a570425ee3a2d88afcc83928fa6ccc5e75aaebebd982180a50c7bb0c856a48c652e3c
7
- data.tar.gz: f76b86b0357b2900a17a4ab7bedfe5a0f52f06254f1fbf10df40a625561437c110aab885588545e2186625c6ddc93aea86aa52fc6e0e88c68c81ab9d4e1f26ee
6
+ metadata.gz: 5de31ef9ff0d7e535ea0ea2f129564c9c8fc43721468ef71149c06df1f8c12bdfec4d8580c111d398cff96e0cec46e40f3bd87928c9ca58bf41f8fd3d58ad88c
7
+ data.tar.gz: 73d37b7cd37e63e0d395657e6fb200db2987f4551fc8c72fb6c0accc275411373cc3163d36af617943f9baf411a6e4b2d36aae404a7a983d91b02b8732eed223
@@ -7,6 +7,15 @@ require 'platform-api'
7
7
  module Hu
8
8
  class Cli < Optix::Cli
9
9
  class Collab < Optix::Cli
10
+ class InvalidOperation < StandardError; end
11
+ class InvalidPlan < StandardError
12
+ attr_accessor :invalid_plan
13
+
14
+ def initialize(message=nil, invalid_plan=nil)
15
+ super(message)
16
+ self.invalid_plan = invalid_plan
17
+ end
18
+ end
10
19
 
11
20
  text "Manage application/collaborator mapping."
12
21
  text ""
@@ -15,23 +24,11 @@ module Hu
15
24
  text ""
16
25
  text "WARNING: If you remove yourself from an application"
17
26
  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
27
  def collab; end
31
28
 
32
29
  OP_COLORS = {
33
30
  '+' => "\e[0;1;32m",
34
- '-' => "\e[0;1;31m",
31
+ '-' => "\e[0;1;34m",
35
32
  '~' => "\e[0;32m",
36
33
  }
37
34
  desc "Read mapping from stdin and diff to heroku state"
@@ -39,14 +36,26 @@ module Hu
39
36
  parent "collab"
40
37
  def diff(cmd, opts, argv)
41
38
  parsed_state = parse_as_json_or_yaml(STDIN.read)
42
- plan(HashDiff.diff(heroku_state['apps'], parsed_state['apps'])).each do |s|
39
+ show_plan( plan(HashDiff.diff(heroku_state['apps'], parsed_state['apps']), opts) )
40
+ end
41
+
42
+ def show_plan(plan)
43
+ plan.each do |s|
43
44
  color = OP_COLORS[s[:op]]
44
45
  msg = ''
46
+ icon = ' '
45
47
  if s[:method].nil?
46
- color = "\e[0;41;33;1m"
47
- msg = "Can not resolve this."
48
+ color = "\e[0m"
49
+ msg = "<-- Can not resolve this (NO-OP)"
50
+ icon = "⚠️"
51
+ elsif s[:invalid]
52
+ color = "\e[0m"
53
+ icon = "⚠️"
54
+ end
55
+ STDERR.printf "%1s %s%6s %-30s %-15s %-30s %s\e[0m\n", icon, color, s[:op_name], s[:app_name], s[:role], s[:value], msg
56
+ if s[:invalid]
57
+ STDERR.puts "\e[31;1m Error: #{s[:invalid]}\e[0m\n\n"
48
58
  end
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
59
  end
51
60
  end
52
61
 
@@ -60,31 +69,46 @@ module Hu
60
69
 
61
70
  desc "Read mapping from stdin and push to heroku"
62
71
  text "Read mapping from stdin and push to heroku"
72
+ opt :allow_create, "Create new collaborators on heroku", :short => 'c'
73
+ opt :silent_create, "Suppress email invitation when creating collaborators"
63
74
  parent "collab"
64
75
  def import(cmd, opts, argv)
65
76
  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
77
+ validators = {
78
+ :op_add_collaborators => Proc.new { |op|
79
+ unless heroku_state['collaborators'].include? op[:value] or opts[:allow_create]
80
+ raise InvalidOperation, "Use -c to allow creation of new collaborator '#{op[:value]}'"
81
+ end
82
+ }
83
+ }
84
+ begin
85
+ plan(HashDiff.diff(heroku_state['apps'], parsed_state['apps']), opts, validators).each do |s|
86
+ color = OP_COLORS[s[:op]]
87
+ msg = ''
88
+ icon = ' '
89
+ eol = "\e[1G"
90
+ if s[:method].nil?
91
+ color = "\e[0;41;33;1m"
92
+ msg = "Skipped."
93
+ icon = "\e[0;31;1m\u2718\e[0m" # X
94
+ eol = "\n"
95
+ end
96
+ 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
97
+ next if s[:method].nil?
98
+ begin
99
+ self.send(s[:method], s)
100
+ STDERR.puts "\e[0;32;1m\u2713\e[0m\n" # check
101
+ rescue => e
102
+ STDERR.puts "\e[0;31;1m\u2718\e[0m\n" # X
103
+ puts e.inspect
104
+ puts e.backtrace
105
+ exit 1
106
+ end
107
+ end # /plan()
108
+ rescue InvalidPlan => e
109
+ STDERR.puts "\e[0;31;1m#{e}:\e[0m\n\n"
110
+ show_plan(e.invalid_plan)
111
+ exit 1
88
112
  end
89
113
  end
90
114
 
@@ -93,8 +117,9 @@ module Hu
93
117
  '-' => 'remove',
94
118
  '~' => 'change',
95
119
  }
96
- def plan(diff)
120
+ def plan(diff, env={}, validators={})
97
121
  plan = []
122
+ last_error = nil
98
123
  diff.each do |op, target, lval, rval|
99
124
  value = rval || lval
100
125
  app_name, role = target.split('.')
@@ -102,20 +127,30 @@ module Hu
102
127
  role = role.split('[')[0] unless role.nil?
103
128
  op_name = OP_MAP[op]
104
129
  method_name = "op_#{op_name}_#{role}".to_sym
105
- plan << {
130
+ operation = {
106
131
  app_name: app_name,
107
132
  op: op,
108
133
  op_name: op_name,
109
134
  method: self.respond_to?(method_name) ? method_name : nil,
110
135
  value: value,
111
136
  role: role,
137
+ env: env,
112
138
  }
139
+ if validators.include? method_name
140
+ begin
141
+ validators[method_name].call(operation)
142
+ rescue InvalidOperation => e
143
+ last_error = operation[:invalid] = e
144
+ end
145
+ end
146
+ plan << operation
113
147
  end
148
+ raise InvalidPlan.new("Plan did not pass validation", plan) unless last_error.nil?
114
149
  plan
115
150
  end
116
151
 
117
152
  def op_add_collaborators(args)
118
- h.collaborator.create(args[:app_name], :user => args[:value])
153
+ h.collaborator.create(args[:app_name], :user => args[:value], :silent => args[:env][:silent_create])
119
154
  end
120
155
 
121
156
  def op_remove_collaborators(args)
@@ -154,11 +189,6 @@ module Hu
154
189
  next unless v['collaborators'].is_a? Array
155
190
  v['collaborators'].flatten!
156
191
  v['collaborators'].sort!
157
- v['collaborators'].each do |collab|
158
- unless heroku_state['collaborators'].include? collab
159
- raise ArgumentError, "Unknown collaborator: #{collab}"
160
- end
161
- end
162
192
  end
163
193
  parsed
164
194
  end
@@ -1,3 +1,3 @@
1
1
  module Hu
2
- VERSION = "1.0.5"
2
+ VERSION = "1.1.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: 1.0.5
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - moe