startapp 0.1.11 → 0.1.13
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/README.md +2 -2
- data/features/app_feature.rb +25 -0
- data/features/core_feature.rb +4 -2
- data/features/members_feature.rb +21 -1
- data/lib/rhc/commands/app.rb +64 -13
- data/lib/rhc/commands/apps.rb +7 -3
- data/lib/rhc/commands/create.rb +2 -1
- data/lib/rhc/commands/domain.rb +2 -1
- data/lib/rhc/commands/member.rb +348 -76
- data/lib/rhc/commands/scp.rb +15 -6
- data/lib/rhc/commands/snapshot.rb +5 -80
- data/lib/rhc/commands/team.rb +103 -0
- data/lib/rhc/context_helper.rb +57 -15
- data/lib/rhc/exceptions.rb +26 -2
- data/lib/rhc/git_helpers.rb +1 -1
- data/lib/rhc/helpers.rb +1 -1
- data/lib/rhc/output_helpers.rb +33 -8
- data/lib/rhc/rest/api.rb +1 -1
- data/lib/rhc/rest/cartridge.rb +6 -1
- data/lib/rhc/rest/client.rb +124 -5
- data/lib/rhc/rest/membership.rb +51 -6
- data/lib/rhc/rest/mock.rb +82 -8
- data/lib/rhc/rest/team.rb +34 -0
- data/lib/rhc/rest.rb +1 -0
- data/lib/rhc/ssh_helpers.rb +88 -0
- data/lib/rhc/usage_templates/command_help.erb +13 -3
- data/lib/rhc/usage_templates/command_syntax_help.erb +11 -0
- data/spec/direct_execution_helper.rb +1 -0
- data/spec/rhc/command_spec.rb +22 -3
- data/spec/rhc/commands/app_spec.rb +81 -3
- data/spec/rhc/commands/apps_spec.rb +41 -1
- data/spec/rhc/commands/domain_spec.rb +1 -1
- data/spec/rhc/commands/member_spec.rb +393 -22
- data/spec/rhc/commands/scp_spec.rb +14 -3
- data/spec/rhc/commands/snapshot_spec.rb +1 -2
- data/spec/rhc/commands/team_spec.rb +191 -0
- data/spec/rhc/helpers_spec.rb +2 -0
- data/spec/rhc/rest_client_spec.rb +23 -0
- data/spec/rhc/rest_spec.rb +5 -5
- data/spec/spec_helper.rb +36 -0
- metadata +8 -2
data/lib/rhc/commands/member.rb
CHANGED
|
@@ -2,75 +2,213 @@ require 'rhc/commands/base'
|
|
|
2
2
|
|
|
3
3
|
module RHC::Commands
|
|
4
4
|
class Member < Base
|
|
5
|
-
summary "Manage membership on domains"
|
|
5
|
+
summary "Manage membership on domains and teams"
|
|
6
6
|
syntax "<action>"
|
|
7
7
|
description <<-DESC
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
Domain Membership
|
|
9
|
+
Developers can collaborate on applications by adding people or teams to
|
|
10
|
+
domains as members. Each member has a role (admin, edit, or view),
|
|
11
|
+
and those roles determine what the user can do with the domain and the
|
|
12
|
+
applications contained within.
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
Domain Member Roles
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
view - able to see the domain and its apps, but not make any changes
|
|
17
|
+
edit - create, update, and delete applications, and has Git and SSH access
|
|
18
|
+
admin - can update membership of a domain
|
|
19
|
+
|
|
20
|
+
The default role granted to domain members is 'edit' - use the '--role'
|
|
21
|
+
argument to specify a different role. When adding and removing members, you
|
|
22
|
+
can use their 'login' value (typically their email or a short unique name for
|
|
23
|
+
them), or their 'id'. Both login and ID are visible via the 'app account'
|
|
24
|
+
command.
|
|
25
|
+
|
|
26
|
+
To see existing members of a domain or application, use:
|
|
27
|
+
|
|
28
|
+
app members -n DOMAIN_NAME [-a APP_NAME]
|
|
29
|
+
|
|
30
|
+
To change the role for a domain member, simply call the update-member command
|
|
31
|
+
with the new role. You cannot change the role of the owner.
|
|
32
|
+
|
|
33
|
+
Team Membership
|
|
34
|
+
People who typically share the same role can be added to a team. The team can
|
|
35
|
+
then be added as a member of a domain, and all of the people in the team will
|
|
36
|
+
inherit the team's role on the domain.
|
|
18
37
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
'id'. Both login and ID are visible via the 'rhc account' command.
|
|
38
|
+
If a person is a member of multiple teams which are members of a domain, or
|
|
39
|
+
is also added as a domain member individually, their effective role is the
|
|
40
|
+
higher of their individual role or their teams' roles on the domain.
|
|
23
41
|
|
|
24
|
-
|
|
42
|
+
Team Member Roles
|
|
43
|
+
view - able to see information about the team and its members, and
|
|
44
|
+
has access to all domains the team is a member of
|
|
25
45
|
|
|
26
|
-
|
|
46
|
+
To see existing members of a team, use:
|
|
47
|
+
|
|
48
|
+
app members -t TEAM_NAME
|
|
27
49
|
|
|
28
|
-
To change the role for a user, simply call the add-member command with the new role. You
|
|
29
|
-
cannot change the role of the owner.
|
|
30
50
|
DESC
|
|
31
51
|
syntax "<action>"
|
|
32
52
|
default_action :help
|
|
33
53
|
|
|
34
|
-
summary "List members of a domain or
|
|
35
|
-
syntax
|
|
54
|
+
summary "List members of a domain, application, or team"
|
|
55
|
+
syntax [
|
|
56
|
+
"<domain_name>[/<app_name>] [--all]",
|
|
57
|
+
"-n DOMAIN_NAME [--all]",
|
|
58
|
+
"-n DOMAIN_NAME -a APP_NAME [--all]",
|
|
59
|
+
nil,
|
|
60
|
+
"-t TEAM_NAME"
|
|
61
|
+
]
|
|
36
62
|
description <<-DESC
|
|
37
|
-
Show the existing members of a domain
|
|
38
|
-
|
|
39
|
-
|
|
63
|
+
Show the existing members of a domain, application, or team.
|
|
64
|
+
|
|
65
|
+
To show the members of a domain or application, you can pass the name of your
|
|
66
|
+
domain with '-n', the name of your application with '-a', or combine them in
|
|
67
|
+
the first argument to the command like:
|
|
68
|
+
app members <domain_name>[/<app_name>]
|
|
40
69
|
|
|
41
|
-
|
|
70
|
+
To show the members of a team, you can pass the name of the team with '-t':
|
|
71
|
+
app members -t TEAM_NAME
|
|
42
72
|
|
|
43
|
-
The owner is always listed first. To see the unique ID of members, pass
|
|
44
|
-
'--ids'.
|
|
73
|
+
The owner is always listed first. To see the unique ID of members, pass '--ids'.
|
|
45
74
|
DESC
|
|
46
75
|
option ['--ids'], "Display the IDs of each member", :optional => true
|
|
47
|
-
|
|
76
|
+
option ['--all'], "Display all members, including members of teams", :optional => true
|
|
77
|
+
takes_membership_container :argument => true
|
|
48
78
|
alias_action :members, :root_command => true
|
|
49
|
-
def list(
|
|
50
|
-
target =
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
m.owner?
|
|
58
|
-
|
|
59
|
-
|
|
79
|
+
def list(_)
|
|
80
|
+
target = find_membership_container
|
|
81
|
+
|
|
82
|
+
members = target.members
|
|
83
|
+
if options.all
|
|
84
|
+
show_members = members.sort
|
|
85
|
+
else
|
|
86
|
+
show_members = members.select do |m|
|
|
87
|
+
if m.owner?
|
|
88
|
+
true
|
|
89
|
+
elsif m.explicit_role?
|
|
90
|
+
true
|
|
91
|
+
elsif m.from.any? {|f| f["type"] != "team" }
|
|
92
|
+
true
|
|
93
|
+
else
|
|
94
|
+
false
|
|
95
|
+
end
|
|
96
|
+
end.sort
|
|
97
|
+
end
|
|
98
|
+
show_name = show_members.any?{ |m| m.name.presence && m.name != m.login }
|
|
99
|
+
show_login = show_members.any?{ |m| m.login.presence }
|
|
100
|
+
|
|
101
|
+
if show_members.present?
|
|
102
|
+
say table(show_members.map do |member|
|
|
103
|
+
[
|
|
104
|
+
((member.name || "") if show_name),
|
|
105
|
+
((member.login || "") if show_login),
|
|
106
|
+
role_description(member, member.teams(members)),
|
|
107
|
+
(member.id if options.ids),
|
|
108
|
+
member.type
|
|
109
|
+
].compact
|
|
110
|
+
end, :header => [
|
|
111
|
+
('Name' if show_name),
|
|
112
|
+
('Login' if show_login),
|
|
113
|
+
'Role',
|
|
114
|
+
("ID" if options.ids),
|
|
115
|
+
"Type"
|
|
116
|
+
].compact)
|
|
117
|
+
else
|
|
118
|
+
info "The #{target.class.model_name.downcase} #{target.name} does not have any members."
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
if show_members.count < members.count
|
|
122
|
+
paragraph do
|
|
123
|
+
info "Pass --all to display all members, including members of teams."
|
|
124
|
+
end
|
|
60
125
|
end
|
|
61
|
-
say table(members, :header => [('Name' if show_name), 'Login', 'Role', ("ID" if options.ids)].compact)
|
|
62
126
|
|
|
63
127
|
0
|
|
64
128
|
end
|
|
65
129
|
|
|
66
|
-
summary "Add
|
|
67
|
-
syntax
|
|
130
|
+
summary "Add a member to a domain or team"
|
|
131
|
+
syntax [
|
|
132
|
+
"-n DOMAIN_NAME [--role view|edit|admin] <login>...",
|
|
133
|
+
"-n DOMAIN_NAME [--role view|edit|admin] <team_name>... --type team [--global]",
|
|
134
|
+
"-n DOMAIN_NAME [--role view|edit|admin] <id>... --ids [--type user|team]",
|
|
135
|
+
nil,
|
|
136
|
+
"-t TEAM_NAME <login>...",
|
|
137
|
+
"-t TEAM_NAME <id>... --ids",
|
|
138
|
+
]
|
|
68
139
|
description <<-DESC
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
140
|
+
Domain Membership
|
|
141
|
+
Add members to a domain by passing a user login, team name, or ID for each
|
|
142
|
+
member. The login and ID for each account are displayed in 'app account'.
|
|
143
|
+
To change the role for an existing domain member, use the 'app member update'
|
|
144
|
+
command.
|
|
145
|
+
|
|
146
|
+
Domain Member Roles
|
|
147
|
+
view - able to see information about the domain and its apps,
|
|
148
|
+
but not make any changes
|
|
149
|
+
edit - create, update, and delete applications, and has Git
|
|
150
|
+
and SSH access
|
|
151
|
+
admin - can update membership of a domain
|
|
152
|
+
|
|
153
|
+
The default role granted to domain members is 'edit'.
|
|
154
|
+
Use the '--role' argument for 'view' or 'admin'.
|
|
155
|
+
|
|
156
|
+
Team Membership
|
|
157
|
+
Add users to a team by passing a user login, or ID for each member.
|
|
158
|
+
|
|
159
|
+
Team Member Roles
|
|
160
|
+
view - able to see information about the team and its members, and
|
|
161
|
+
has access to all domains the team is a member of
|
|
162
|
+
|
|
163
|
+
Examples
|
|
164
|
+
app add-member sally joe -n mydomain
|
|
165
|
+
Gives the accounts with logins 'sally' and 'joe' edit access on mydomain
|
|
166
|
+
|
|
167
|
+
app add-member bob --role admin -n mydomain
|
|
168
|
+
Gives the account with login 'bob' admin access on mydomain
|
|
169
|
+
|
|
170
|
+
app add-member team1 --type team --role admin -n mydomain
|
|
171
|
+
Gives your team named 'team1' admin access on mydomain
|
|
172
|
+
|
|
173
|
+
app add-member steve -t team1
|
|
174
|
+
Adds the account with login 'steve' as a member of your team named 'team1'
|
|
175
|
+
DESC
|
|
176
|
+
takes_membership_container :writable => true
|
|
177
|
+
option ['--ids'], "Add member(s) by ID", :optional => true
|
|
178
|
+
option ['-r', '--role ROLE'], "The role to give to each member - view, edit, or admin (default is 'edit' for domains, 'view' for teams)", :type => Role, :optional => true
|
|
179
|
+
option ['--type TYPE'], "Type of member(s) being added - user or team (default is 'user').", :optional => true
|
|
180
|
+
option ['--global'], "Add global-scoped teams as members. Must be used with '--type team'.", :optional => true
|
|
181
|
+
argument :members, "A list of members (user logins, team names, or IDs) to add. Pass --ids to treat this as a list of IDs.", [], :type => :list
|
|
182
|
+
def add(members)
|
|
183
|
+
target = find_membership_container :writable => true
|
|
184
|
+
|
|
185
|
+
role = get_role_option(options, target)
|
|
186
|
+
type = get_type_option(options)
|
|
187
|
+
global = !!options.global
|
|
188
|
+
|
|
189
|
+
raise ArgumentError, 'You must pass at least one member to this command.' unless members.present?
|
|
190
|
+
raise ArgumentError, "The --global option can only be used with '--type team'." if global && !team?(type)
|
|
191
|
+
|
|
192
|
+
say "Adding #{pluralize(members.length, role_name(role))} to #{target.class.model_name.downcase} ... "
|
|
193
|
+
|
|
194
|
+
members = search_teams(members, global).map{|member| member.id} if team?(type) && !options.ids
|
|
195
|
+
target.update_members(changes_for(members, role, type))
|
|
196
|
+
|
|
197
|
+
success "done"
|
|
198
|
+
|
|
199
|
+
0
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
summary "Update a member on a domain"
|
|
203
|
+
syntax [
|
|
204
|
+
"-n DOMAIN_NAME --role view|edit|admin <login>...",
|
|
205
|
+
"-n DOMAIN_NAME --role view|edit|admin <team_name>... --type team",
|
|
206
|
+
"-n DOMAIN_NAME --role view|edit|admin <id>... --ids [--type user|team]",
|
|
207
|
+
]
|
|
208
|
+
description <<-DESC
|
|
209
|
+
Updates members on a domain by passing a user login, team name, or ID for
|
|
210
|
+
each member. You can use the 'app members' command to list the existing
|
|
211
|
+
members of your domain. You cannot change the role of the owner.
|
|
74
212
|
|
|
75
213
|
Roles
|
|
76
214
|
view - able to see information about the domain and its apps,
|
|
@@ -79,47 +217,67 @@ module RHC::Commands
|
|
|
79
217
|
and SSH access
|
|
80
218
|
admin - can update membership of a domain
|
|
81
219
|
|
|
82
|
-
The default role granted to members when added is 'edit' - use the '--role'
|
|
83
|
-
argument for 'view' or 'admin'.
|
|
84
|
-
|
|
85
220
|
Examples
|
|
86
|
-
|
|
87
|
-
|
|
221
|
+
app update-member -n mydomain --role view bob
|
|
222
|
+
Adds or updates the user with login 'bob' to 'admin' role on mydomain
|
|
88
223
|
|
|
89
|
-
|
|
90
|
-
|
|
224
|
+
app update-member -n mydomain --role admin team1 --type team
|
|
225
|
+
Updates the team member with name 'team1' to the 'admin' role on mydomain
|
|
226
|
+
|
|
227
|
+
app update-member -n mydomain --role admin team1_id --ids --type team
|
|
228
|
+
Adds or updates the team with ID 'team1_id' to the 'admin' role on mydomain
|
|
91
229
|
|
|
92
230
|
DESC
|
|
93
231
|
takes_domain
|
|
94
|
-
option ['--ids'], "
|
|
95
|
-
option ['-r', '--role ROLE'], "The role to give to each member - view, edit, or admin
|
|
96
|
-
|
|
97
|
-
|
|
232
|
+
option ['--ids'], "Update member(s) by ID", :optional => true
|
|
233
|
+
option ['-r', '--role ROLE'], "The role to give to each member - view, edit, or admin", :type => Role, :optional => false
|
|
234
|
+
option ['--type TYPE'], "Type of member(s) being updated - user or team (default is 'user').", :optional => true
|
|
235
|
+
argument :members, "A list of members (user logins, team names, or IDs) to update. Pass --ids to treat this as a list of IDs.", [], :type => :list
|
|
236
|
+
def update(members)
|
|
98
237
|
target = find_domain
|
|
99
|
-
role = options
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
238
|
+
role = get_role_option(options, target)
|
|
239
|
+
type = get_type_option(options)
|
|
240
|
+
|
|
241
|
+
raise ArgumentError, 'You must pass at least one member to this command.' unless members.present?
|
|
242
|
+
|
|
243
|
+
say "Updating #{pluralize(members.length, role_name(role))} to #{target.class.model_name.downcase} ... "
|
|
244
|
+
|
|
245
|
+
members = search_team_members(target.members, members).map{|member| member.id} if team?(type) && !options.ids
|
|
246
|
+
target.update_members(changes_for(members, role, type))
|
|
247
|
+
|
|
103
248
|
success "done"
|
|
104
249
|
|
|
105
250
|
0
|
|
106
251
|
end
|
|
107
252
|
|
|
108
|
-
summary "Remove a member from a domain"
|
|
109
|
-
syntax
|
|
253
|
+
summary "Remove a member from a domain or team"
|
|
254
|
+
syntax [
|
|
255
|
+
"-n DOMAIN_NAME <login>...",
|
|
256
|
+
"-n DOMAIN_NAME <team_name>... --type team",
|
|
257
|
+
"-n DOMAIN_NAME <id>... --ids [--type user|team]",
|
|
258
|
+
nil,
|
|
259
|
+
"-t TEAM_NAME <login>...",
|
|
260
|
+
"-t TEAM_NAME <id>... --ids",
|
|
261
|
+
]
|
|
110
262
|
description <<-DESC
|
|
111
|
-
Remove members
|
|
263
|
+
Remove members from a domain by passing a user login, team name, or ID for each
|
|
264
|
+
member you wish to remove. View the list of existing members with
|
|
265
|
+
app members -n DOMAIN_NAME
|
|
266
|
+
|
|
267
|
+
Remove members from a team by passing a user login, or ID for each
|
|
112
268
|
member you wish to remove. View the list of existing members with
|
|
113
|
-
|
|
269
|
+
app members -t TEAM_NAME
|
|
114
270
|
|
|
115
|
-
Pass '--all' to remove all but the owner
|
|
271
|
+
Pass '--all' to remove all members but the owner.
|
|
116
272
|
DESC
|
|
117
|
-
|
|
118
|
-
option ['--ids'], "
|
|
119
|
-
option ['--all'], "Remove all members
|
|
120
|
-
|
|
273
|
+
takes_membership_container :writable => true
|
|
274
|
+
option ['--ids'], "Remove member(s) by ID."
|
|
275
|
+
option ['--all'], "Remove all members"
|
|
276
|
+
option ['--type TYPE'], "Type of member(s) being removed - user or team (default is 'user').", :optional => true
|
|
277
|
+
argument :members, "A list of members (user logins, team names, or IDs) to remove. Pass --ids to treat this as a list of IDs.", [], :type => :list
|
|
121
278
|
def remove(members)
|
|
122
|
-
target =
|
|
279
|
+
target = find_membership_container :writable => true
|
|
280
|
+
type = get_type_option(options)
|
|
123
281
|
|
|
124
282
|
if options.all
|
|
125
283
|
say "Removing all members from #{target.class.model_name.downcase} ... "
|
|
@@ -127,9 +285,13 @@ module RHC::Commands
|
|
|
127
285
|
success "done"
|
|
128
286
|
|
|
129
287
|
else
|
|
130
|
-
raise ArgumentError, 'You must pass
|
|
288
|
+
raise ArgumentError, 'You must pass at least one member to this command.' unless members.present?
|
|
289
|
+
|
|
131
290
|
say "Removing #{pluralize(members.length, 'member')} from #{target.class.model_name.downcase} ... "
|
|
132
|
-
|
|
291
|
+
|
|
292
|
+
members = search_team_members(target.members, members).map{|member| member.id} if team?(type) && !options.ids
|
|
293
|
+
target.update_members(changes_for(members, 'none', type))
|
|
294
|
+
|
|
133
295
|
success "done"
|
|
134
296
|
end
|
|
135
297
|
|
|
@@ -137,12 +299,122 @@ module RHC::Commands
|
|
|
137
299
|
end
|
|
138
300
|
|
|
139
301
|
protected
|
|
140
|
-
def
|
|
302
|
+
def get_role_option(options, target)
|
|
303
|
+
options.role || target.default_member_role
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def get_type_option(options)
|
|
307
|
+
type = options.__hash__[:type]
|
|
308
|
+
type || 'user'
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def changes_for(members, role, type)
|
|
141
312
|
members.map do |m|
|
|
142
|
-
h = {:role => role}
|
|
143
|
-
h[options.ids ? :id : :login] = m
|
|
313
|
+
h = {:role => role, :type => type}
|
|
314
|
+
h[options.ids || team?(type) ? :id : :login] = m
|
|
144
315
|
h
|
|
145
316
|
end
|
|
146
317
|
end
|
|
318
|
+
|
|
319
|
+
def team?(type)
|
|
320
|
+
type == 'team'
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def search_teams(team_names, global=false)
|
|
324
|
+
r = []
|
|
325
|
+
team_names.each do |team_name|
|
|
326
|
+
teams_for_name =
|
|
327
|
+
global ?
|
|
328
|
+
rest_client.search_teams(team_name, global) :
|
|
329
|
+
rest_client.search_owned_teams(team_name)
|
|
330
|
+
|
|
331
|
+
team_for_name = nil
|
|
332
|
+
suggestions = nil
|
|
333
|
+
|
|
334
|
+
if (exact_matches = teams_for_name.select {|t| t.name == team_name }).present?
|
|
335
|
+
if exact_matches.length == 1
|
|
336
|
+
team_for_name = exact_matches.first
|
|
337
|
+
else
|
|
338
|
+
raise RHC::TeamNotFoundException.new("There is more than one team named '#{team_name}'. " +
|
|
339
|
+
"Please use the --ids flag and specify the exact id of the team you want to manage.")
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
elsif (case_insensitive_matches = teams_for_name.select {|t| t.name =~ /^#{Regexp.escape(team_name)}$/i }).present?
|
|
343
|
+
if case_insensitive_matches.length == 1
|
|
344
|
+
team_for_name = case_insensitive_matches.first
|
|
345
|
+
else
|
|
346
|
+
suggestions = case_insensitive_matches
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
else
|
|
350
|
+
suggestions = teams_for_name
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
if team_for_name
|
|
355
|
+
r << team_for_name
|
|
356
|
+
elsif suggestions.present?
|
|
357
|
+
msg = global ? "No global team found with the name '#{team_name}'." : "You do not have a team named '#{team_name}'."
|
|
358
|
+
raise RHC::TeamNotFoundException.new(msg + " Did you mean one of the following?\n#{suggestions[0..50].map(&:name).join(", ")}")
|
|
359
|
+
else
|
|
360
|
+
msg = global ? "No global team found with the name '#{team_name}'." : "You do not have a team named '#{team_name}'."
|
|
361
|
+
raise RHC::TeamNotFoundException.new(msg)
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
end
|
|
365
|
+
r.flatten
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def search_team_members(members, names)
|
|
369
|
+
r = []
|
|
370
|
+
team_members = members.select(&:team?)
|
|
371
|
+
names.each do |name|
|
|
372
|
+
|
|
373
|
+
team_for_name = nil
|
|
374
|
+
suggestions = nil
|
|
375
|
+
|
|
376
|
+
if (exact_matches = team_members.select{|team| team.name == name }).present?
|
|
377
|
+
if exact_matches.length == 1
|
|
378
|
+
team_for_name = exact_matches.first
|
|
379
|
+
else
|
|
380
|
+
raise RHC::MemberNotFoundException.new("There is more than one member team named '#{name}'. " +
|
|
381
|
+
"Please use the --ids flag and specify the exact id of the team you want to manage.")
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
elsif (case_insensitive_matches = team_members.select{|team| team.name =~ /^#{Regexp.escape(name)}$/i}).present?
|
|
385
|
+
if case_insensitive_matches.length == 1
|
|
386
|
+
team_for_name = case_insensitive_matches.first
|
|
387
|
+
else
|
|
388
|
+
suggestions = case_insensitive_matches
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
else
|
|
392
|
+
suggestions = team_members.select{|t| t.name =~ /#{Regexp.escape(name)}/i}
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
if team_for_name
|
|
396
|
+
r << team_for_name
|
|
397
|
+
elsif suggestions.present?
|
|
398
|
+
raise RHC::MemberNotFoundException.new("No member team found with the name '#{name}'. " +
|
|
399
|
+
"Did you mean one of the following?\n#{suggestions[0..50].map(&:name).join(", ")}")
|
|
400
|
+
else
|
|
401
|
+
raise RHC::MemberNotFoundException.new("No member team found with the name '#{name}'.")
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
end
|
|
405
|
+
r.flatten
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def role_description(member, teams=[])
|
|
409
|
+
if member.owner?
|
|
410
|
+
"#{member.role} (owner)"
|
|
411
|
+
elsif member.explicit_role != member.role && member.from.all? {|f| f['type'] == 'domain'}
|
|
412
|
+
"#{member.role} (via domain)"
|
|
413
|
+
elsif member.explicit_role != member.role && teams.present? && (teams_with_role = teams.select{|t| t.role == member.role }).present?
|
|
414
|
+
"#{member.role} (via #{teams_with_role.map(&:name).sort.join(', ')})"
|
|
415
|
+
else
|
|
416
|
+
member.role
|
|
417
|
+
end
|
|
418
|
+
end
|
|
147
419
|
end
|
|
148
|
-
end
|
|
420
|
+
end
|
data/lib/rhc/commands/scp.rb
CHANGED
|
@@ -13,7 +13,7 @@ module RHC::Commands
|
|
|
13
13
|
cartridge) by default.
|
|
14
14
|
|
|
15
15
|
Examples:
|
|
16
|
-
Uploading a file from your
|
|
16
|
+
Uploading a file from your working directory to your app-root/data directory
|
|
17
17
|
app scp myapp upload somefile.txt app-root/data
|
|
18
18
|
|
|
19
19
|
Downloading a file from your app-root/data directory to your working directory
|
|
@@ -21,9 +21,9 @@ module RHC::Commands
|
|
|
21
21
|
DESC
|
|
22
22
|
syntax "[<app> --] <action> <local_path> <remote_path>"
|
|
23
23
|
takes_application :argument => true
|
|
24
|
-
argument :action, "Transfer direction: upload|download", ["-t", "--
|
|
25
|
-
argument :local_path, "Local filesystem path", ["-
|
|
26
|
-
argument :remote_path, "Remote filesystem path", ["-r", "--
|
|
24
|
+
argument :action, "Transfer direction: upload|download", ["-t", "--transfer-direction upload|download"], :optional => false
|
|
25
|
+
argument :local_path, "Local filesystem path", ["-f", "--local-path file_path"], :optional => false
|
|
26
|
+
argument :remote_path, "Remote filesystem path", ["-r", "--remote-path file_path"], :optional => false
|
|
27
27
|
alias_action 'app scp', :root_command => true
|
|
28
28
|
def run(_, action, local_path, remote_path)
|
|
29
29
|
rest_app = find_app
|
|
@@ -34,17 +34,26 @@ module RHC::Commands
|
|
|
34
34
|
|
|
35
35
|
begin
|
|
36
36
|
start_time = Time.now
|
|
37
|
+
last_sent = nil
|
|
37
38
|
Net::SCP.send("#{action}!".to_sym, ssh_opts[1], ssh_opts[0], (action == 'upload' ? local_path : remote_path), (action == 'upload' ? remote_path : local_path)) do |ch, name, sent, total|
|
|
38
39
|
#:nocov:
|
|
39
|
-
|
|
40
|
+
if sent != last_sent
|
|
41
|
+
last_sent = sent
|
|
42
|
+
complete = total == 0 ? 100 : ((sent.to_f/total.to_f)*100).to_i
|
|
43
|
+
$stderr.print "\r #{action}ing #{name}: #{complete}% complete. #{sent}/#{total} bytes transferred " + (sent == total ? "in #{Time.now - start_time} seconds \n" : "")
|
|
44
|
+
end
|
|
40
45
|
#:nocov:
|
|
41
46
|
end
|
|
42
47
|
rescue Errno::ECONNREFUSED
|
|
43
48
|
raise RHC::SSHConnectionRefused.new(ssh_opts[0], ssh_opts[1])
|
|
44
49
|
rescue SocketError => e
|
|
45
50
|
raise RHC::ConnectionFailed, "The connection to #{ssh_opts[1]} failed: #{e.message}"
|
|
51
|
+
rescue Net::SSH::AuthenticationFailed => e
|
|
52
|
+
debug_error e
|
|
53
|
+
raise RHC::SSHAuthenticationFailed.new(ssh_opts[1], ssh_opts[0])
|
|
46
54
|
rescue Net::SCP::Error => e
|
|
47
|
-
|
|
55
|
+
debug_error e
|
|
56
|
+
raise RHC::RemoteFileOrPathNotFound.new("An unknown error occurred: #{e.message}")
|
|
48
57
|
end
|
|
49
58
|
end
|
|
50
59
|
|