labclient 0.1.3 → 0.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab2d7a4a0dcf9e876c42f3d92537ad03f6cc9d00391bf574188de36fa5dde3a6
4
- data.tar.gz: 9bba10386c15059b97c79a0e6f0ed322af7614736b78e55fd968f362e767dd8e
3
+ metadata.gz: '09bb30f5014cb0b4a37d7f4aa421549337b6177bf132580974cf1a35199c6242'
4
+ data.tar.gz: cc354dc398276bba64db00bc9adafd23e9c341eba16c4c2dd315788f3ab72fb1
5
5
  SHA512:
6
- metadata.gz: 8998430e5b8d07584da6fe906d465238fd7725fa0773b9bb11a7b47dc755ce5fcb80d0cbb22055b16327665d70cbd034a24a63d310fabd11bd560c0ebd994f95
7
- data.tar.gz: 3e61e5c568a93cfad5955198f6524349a89a06d729ead2d8f98c1d05c78e885edfb9fbb069fee2226731b26a1ab8c0404b857883f745d99c7564280e8f855b4d
6
+ metadata.gz: f492cb23a182293f165733d7d54830a2a34b9666c487cf63b5bd2dded2dbd58a7713f513eeba0813e382f1efe0d2c50cb8204f485678448b76f109bf289b8887
7
+ data.tar.gz: 0d558d85cea6f58bddf600dd36962b9a3fe1bc0c91e9b398ff6d2c35103fd61d88e4b6d47d24aa06bff15a5c2c195561847f495400ddef1eabaf78cfd7c65498
@@ -36,7 +36,6 @@ require 'labclient/users/current'
36
36
  require 'labclient/users/status'
37
37
  require 'labclient/users/counts'
38
38
  require 'labclient/users/activity'
39
- require 'labclient/users/memberships'
40
39
  require 'labclient/users/search'
41
40
  require 'labclient/users/create'
42
41
  require 'labclient/users/update'
@@ -47,6 +46,8 @@ require 'labclient/users/activate'
47
46
  require 'labclient/users/deactivate'
48
47
  require 'labclient/users/delete'
49
48
  require 'labclient/users/delete_identity'
49
+ require 'labclient/users/memberships'
50
+ require 'labclient/users/membership'
50
51
  require 'labclient/users/user'
51
52
 
52
53
  # ===============================================
@@ -149,6 +150,13 @@ require 'labclient/projects/environments/delete'
149
150
  require 'labclient/projects/environments/stop'
150
151
  require 'labclient/projects/environments/project_environment'
151
152
 
153
+ # Protected Environments
154
+ require 'labclient/protected_environments/list'
155
+ require 'labclient/protected_environments/show'
156
+ require 'labclient/protected_environments/protect'
157
+ require 'labclient/protected_environments/unprotect'
158
+ require 'labclient/protected_environments/protected_environment'
159
+
152
160
  # Project Deployments
153
161
  require 'labclient/projects/deployments/client'
154
162
  require 'labclient/projects/deployments/list'
@@ -1,6 +1,7 @@
1
1
  # Top Namespace
2
2
  module LabClient
3
3
  # API Specifics
4
+ # rubocop:disable Metrics/ClassLength
4
5
  class Client
5
6
  # include HTTParty
6
7
  attr_accessor :settings, :resp, :klass, :link, :http
@@ -55,6 +56,7 @@ module LabClient
55
56
  project_runners: ProjectRunners,
56
57
  projects: Projects,
57
58
  protected_branches: ProtectedBranches,
59
+ protected_environments: ProtectedEnvironments,
58
60
  protected_tags: ProtectedTags,
59
61
  registry: Registry,
60
62
  repo: Repositories,
@@ -91,18 +93,33 @@ module LabClient
91
93
  end
92
94
 
93
95
  # Default setup, pull in settings
94
- def initialize(settings = nil)
95
- @settings = settings
96
+ def initialize(user_settings = nil)
97
+ @settings = user_settings
98
+ setup_profile if user_settings&.key?(:profile) || ENV['LABCLIENT_PROFILE']
96
99
  @settings ||= fill_configuration
97
100
 
98
101
  # Set Unspecified Defaults
99
102
  unspecified_defaults
100
103
 
101
- raise 'LabClient Error - Missing URL!' if @settings[:url].nil?
104
+ prompt_for_url if @settings[:url].blank?
105
+
106
+ # Only prompt if explicitly set to nil
107
+ prompt_for_token if @settings[:token].nil?
102
108
 
103
109
  self.http = HTTP.new(@settings)
104
110
  end
105
111
 
112
+ def prompt_for_url
113
+ print 'Enter GitLab URL (e.g. https://gitlab.com): '
114
+ @settings[:url] = STDIN.gets.chomp
115
+ raise 'LabClient Error - Missing URL!' if @settings[:url].blank?
116
+ end
117
+
118
+ def prompt_for_token
119
+ print 'Enter Personal Access Token: '
120
+ @settings[:token] = STDIN.gets.chomp
121
+ end
122
+
106
123
  def unspecified_defaults
107
124
  @settings[:paginate] = true if @settings[:paginate].nil?
108
125
  @settings[:ssl_verify] = true if @settings[:ssl_verify].nil?
@@ -112,6 +129,27 @@ module LabClient
112
129
  ENV['HOME'] + '/.gitlab-labclient'
113
130
  end
114
131
 
132
+ # Easier Profile Name Access
133
+ def profile
134
+ if settings&.key? :profile
135
+ settings[:profile].to_sym
136
+ else
137
+ ENV['LABCLIENT_PROFILE'].to_sym
138
+ end
139
+ end
140
+
141
+ # Support for Named Profiles
142
+ def setup_profile
143
+ return false unless File.exist? home_file
144
+
145
+ config = Oj.load_file(home_file, { symbol_keys: true })
146
+ return false unless config.key? profile
147
+
148
+ self.settings ||= {}
149
+ settings.merge! config[profile]
150
+ end
151
+
152
+ # Load default profile
115
153
  def fill_configuration
116
154
  if File.exist? home_file
117
155
  Oj.load_file(home_file, { symbol_keys: true })
@@ -155,4 +193,5 @@ module LabClient
155
193
  end
156
194
  end
157
195
  end
196
+ # rubocop:enable Metrics/ClassLength
158
197
  end
@@ -43,13 +43,13 @@ module LabClient
43
43
 
44
44
  doc 'Wizard' do
45
45
  markdown <<~DOC
46
- | Setting | Type | Description |
47
- | -------- | ------- | ------------------------------------------------------ |
48
- | random | Boolean | Run Populate. Setup random Users, Projects, and Groups |
49
- | count | Hash | Settings for random. User, Project, Group count |
50
- | password | String | Default password for generated Users |
51
- | domain | String | Defaults to client url. Default email domain for users |
52
-
46
+ | Setting | Type | Description |
47
+ | ----------------- | ------- | ------------------------------------------------------ |
48
+ | random | Boolean | Run Populate. Setup random Users, Projects, and Groups |
49
+ | count | Hash | Settings for random. User, Project, Group count |
50
+ | password | String | Default password for generated Users |
51
+ | domain | String | Defaults to client url. Default email domain for users |
52
+ | skip_confirmation | Boolean | Enable/Disable skip_confirmation on new users |
53
53
  DOC
54
54
  end
55
55
 
@@ -5,7 +5,7 @@ module LabClient
5
5
  class Wizard
6
6
  include Generator::Names # Name Generator
7
7
  attr_reader :client
8
- attr_accessor :count, :random, :password, :templates, :domain
8
+ attr_accessor :count, :random, :password, :templates, :domain, :skip_confirmation
9
9
 
10
10
  def inspect
11
11
  "#<Wizard count=#{count}, random=#{random}, domain=#{domain}> templates=#{templates}"
@@ -26,6 +26,9 @@ module LabClient
26
26
  self.random = true # Populate Random or use only Templates
27
27
  self.count = default_count
28
28
  self.password = SecureRandom.uuid
29
+ puts "Default Password: #{password}"
30
+
31
+ self.skip_confirmation = true
29
32
  self.domain = URI.parse(client.settings[:url]).hostname
30
33
 
31
34
  # Default Templates
@@ -61,7 +64,8 @@ module LabClient
61
64
  name: name,
62
65
  email: email,
63
66
  password: password,
64
- username: username
67
+ username: username,
68
+ skip_confirmation: skip_confirmation
65
69
  )
66
70
  end
67
71
  end
@@ -51,6 +51,7 @@ module LabClient
51
51
  option 'level', 'Humanized symbol of access level. e.g. :developer'
52
52
  option 'user', 'Collect user object.'
53
53
  option '<permission>?', 'True/False evaluation each guest?, developer? etc'
54
+ option 'greater_than', 'True/False if user has greater than [Permission Name]'
54
55
  end
55
56
  end
56
57
  end
@@ -44,6 +44,41 @@ module LabClient
44
44
  DOC
45
45
  end
46
46
 
47
+ doc 'Authentication' do
48
+ title 'Named Profiles'
49
+ markdown 'Within the `~/.gitlab-labclient` you can also specify profile names'
50
+ example <<~DOC
51
+ {
52
+ "prod": {
53
+ "url": "https://labclient-prod",
54
+ "token": "super_secure",
55
+ "paginate": false
56
+ },
57
+ "dev": {
58
+ "url": "https://labclient-dev",
59
+ "token": "super_secure",
60
+ "ssl_verify": false,
61
+ "paginate": true
62
+ }
63
+ }
64
+ DOC
65
+ end
66
+
67
+ doc 'Authentication' do
68
+ desc 'Manually select a named profile'
69
+ example <<~DOC
70
+ client = LabClient::Client.new(profile: 'prod')
71
+ DOC
72
+ end
73
+
74
+ doc 'Authentication' do
75
+ desc 'Automatically select via ENV Variables'
76
+ example <<~DOC
77
+ ENV['LABCLIENT_PROFILE'] = 'dev'
78
+ client = LabClient::Client.new
79
+ DOC
80
+ end
81
+
47
82
  doc 'Authentication' do
48
83
  title 'Environment Variables'
49
84
  desc 'If not provided, and credentials file does not exist will attempt to use ENV variables'
@@ -252,21 +287,6 @@ module LabClient
252
287
  DOC
253
288
  end
254
289
 
255
- doc 'Other' do
256
- title 'Docker'
257
- desc 'A docker image is created from master and can be used to execute snippets or load a quick pry session'
258
-
259
- example 'docker run -it registry.gitlab.com/labclient/labclient'
260
-
261
- result <<~DOC
262
- # Run Container
263
- docker run -it -e LABCLIENT_URL="https://labclient" -e LABCLIENT_TOKEN="token" registry.gitlab.com/labclient/labclient
264
-
265
- client = LabClient::Client.new
266
- client.users.list
267
- DOC
268
- end
269
-
270
290
  doc 'Other' do
271
291
  title 'Curl'
272
292
  desc 'Sometimes you just wana have a curl example to test or send someone'
@@ -291,6 +311,30 @@ module LabClient
291
311
  - [API Authentication](https://docs.gitlab.com/ee/api/README.html#authentication)
292
312
  DOC
293
313
  end
314
+
315
+ doc 'Docker' do
316
+ desc 'A docker image is created from master and can be used to execute snippets or load a quick pry session'
317
+
318
+ example 'docker run -it registry.gitlab.com/labclient/labclient'
319
+
320
+ result <<~DOC
321
+ # Run Container
322
+ docker run -it registry.gitlab.com/labclient/labclient
323
+ # Without settings configured, initial will prompt for credentials
324
+
325
+ client.users.list
326
+ DOC
327
+ end
328
+
329
+ doc 'Docker' do
330
+ desc 'The docker container configured and execute code snippets'
331
+
332
+ example 'docker run -it registry.gitlab.com/labclient/labclient'
333
+
334
+ result <<~DOC
335
+ docker run -it -e LABCLIENT_URL="https://labclient" -e LABCLIENT_TOKEN="secure_token" labclient 'puts client.users.list.count'
336
+ DOC
337
+ end
294
338
  end
295
339
  end
296
340
  # rubocop:enable Metrics/ClassLength
@@ -492,6 +492,23 @@ module LabClient
492
492
  client.projects.environments.stop(id, environment_id)
493
493
  end
494
494
 
495
+ # Protected Environments
496
+ def protected_environments
497
+ client.protected_environments.list(id)
498
+ end
499
+
500
+ def protected_environment(environment_id)
501
+ client.protected_environments.show(id, environment_id)
502
+ end
503
+
504
+ def protect_environment(query)
505
+ client.protected_environments.protect(id, query)
506
+ end
507
+
508
+ def unprotect_environment(environment_id)
509
+ client.protected_environments.unprotect(id, environment_id)
510
+ end
511
+
495
512
  # Project Triggers
496
513
  def triggers
497
514
  client.projects.triggers.list(id)
@@ -71,6 +71,12 @@ module LabClient
71
71
  option 'environment_update', 'Update project environment [Environment ID, Hash]'
72
72
  option 'environment_stop', 'Stop project environment [Environment ID]'
73
73
 
74
+ # Protected Environments
75
+ option 'protected_environments', 'List protected environments [String]'
76
+ option 'protected_environment', 'Show single protected environment [String]'
77
+ option 'protect_environment', 'Protect a single environment [Hash]'
78
+ option 'unprotect_environment', 'Unprotect environment [Environment]'
79
+
74
80
  # Deployments
75
81
  option 'deployments', "List this project's deployments"
76
82
  option 'deployment_create', 'Create project deployment [Hash]'
@@ -19,11 +19,12 @@ module LabClient
19
19
  | allowed_to_unprotect | array | no | **(STARTER)** Array of access levels allowed to unprotect, with each described by a hash |
20
20
  | code_owner_approval_required | boolean | no | **(PREMIUM)** Prevent pushes to this branch if it matches an item in the CODEOWNERS file (defaults: false) |
21
21
 
22
- *Valid access levels*
23
- 0 => No access, :none
24
- 30 => Developer access, :developer
25
- 40 => Maintainer access, :maintainer
26
- 60 => Admin access, :admin
22
+ **Valid access levels**
23
+
24
+ - 0, :none => No access
25
+ - 30, :developer => Developer access
26
+ - 40, :maintainer => Maintainer access
27
+ - 60, :admin => Admin access
27
28
 
28
29
  DOC
29
30
  end
@@ -0,0 +1,29 @@
1
+ # Top namespace
2
+ module LabClient
3
+ # Specifics
4
+ class ProtectedEnvironments < Common
5
+ doc 'List' do
6
+ desc 'Gets a list of protected environmentes from a project. [Project ID, String]'
7
+ example 'client.protected_environments.list(36)'
8
+ result '[#<ProtectedEnvironment name: prod>]'
9
+
10
+ markdown <<~DOC
11
+ Search: You can use ^term and term$ to find environmentes that begin and end with term respectively.
12
+ DOC
13
+ end
14
+
15
+ doc 'List' do
16
+ desc 'via Project'
17
+ example <<~DOC
18
+ project = client.projects.show(264)
19
+ project.protected_environments
20
+ DOC
21
+ end
22
+
23
+ def list(project_id)
24
+ project_id = format_id(project_id)
25
+
26
+ client.request(:get, "projects/#{project_id}/protected_environments", ProtectedEnvironment)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,53 @@
1
+ # Top namespace
2
+ module LabClient
3
+ # Specifics
4
+ class ProtectedEnvironments < Common
5
+ doc 'Protect' do
6
+ desc 'Protects a single environment [Project ID, Hash]'
7
+ example <<~DOC
8
+ client.protected_environments.protect(36,
9
+ name: :prod,
10
+ deploy_access_levels: [
11
+ { access_level: :developer }
12
+ ]
13
+ )
14
+ DOC
15
+ result '#<ProtectedEnvironment name: prod>'
16
+
17
+ markdown <<~DOC
18
+ | Attribute | Type | Required | Description |
19
+ | -------------------- | -------------- | -------- | ---------------------------------------------------------------------------------------------------------------- |
20
+ | name | string | yes | The name of the environment. |
21
+ | deploy_access_levels | array | yes | Array of access levels allowed to deploy, with each described by a hash. |
22
+
23
+ Elements in the deploy_access_levels array should take the form {user_id: integer}, {group_id: integer} or {access_level: integer}. Each user must have access to the project and each group must have this project shared.
24
+
25
+ **Valid access levels**
26
+
27
+ | Access Level | Values |
28
+ | ------------ | --------------- |
29
+ | Developer | 30, :developer |
30
+ | Maintainer | 40, :maintainer |
31
+ | Admin | 60, :admin |
32
+
33
+ DOC
34
+ end
35
+
36
+ doc 'Protect' do
37
+ desc 'via Project'
38
+ example <<~DOC
39
+ project = client.projects.show(264)
40
+ project.protect_environment(name: :other, push_access_level: :admin)
41
+ DOC
42
+ end
43
+
44
+ def protect(project_id, query)
45
+ query[:deploy_access_levels].each do |access_level|
46
+ protected_query_access_level(access_level, :access_level)
47
+ end
48
+
49
+ project_id = format_id(project_id)
50
+ client.request(:post, "projects/#{project_id}/protected_environments", ProtectedEnvironment, query)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,22 @@
1
+ # Top namespace
2
+ module LabClient
3
+ # Inspect Helper
4
+ class ProtectedEnvironment < Klass
5
+ include ClassHelpers
6
+ def inspect
7
+ "#<ProtectedEnvironment name: #{name}>"
8
+ end
9
+
10
+ def unprotect
11
+ project_id = collect_project_id
12
+
13
+ client.protected_environments.unprotect(project_id, name)
14
+ end
15
+
16
+ help do
17
+ subtitle 'ProjectEnvironment'
18
+ option 'project', 'Show Project'
19
+ option 'unprotect', 'Remove protected environment'
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ # Top namespace
2
+ module LabClient
3
+ # Specifics
4
+ class ProtectedEnvironments < Common
5
+ doc 'Show' do
6
+ desc 'Gets a single protected environment [Project ID, ProtectedEnvironment]'
7
+ example 'client.protected_environments.show(36, :prod)'
8
+ result '#<ProtectedEnvironment name: prod>'
9
+ end
10
+
11
+ doc 'Show' do
12
+ desc 'via Project'
13
+ example <<~DOC
14
+ project = client.projects.show(264)
15
+ project.protected_environment(:master)
16
+ DOC
17
+ end
18
+
19
+ def show(project_id, environment_id)
20
+ project_id = format_id(project_id)
21
+ client.request(:get, "projects/#{project_id}/protected_environments/#{environment_id}", ProtectedEnvironment)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ # Top namespace
2
+ module LabClient
3
+ # Specifics
4
+ class ProtectedEnvironments < Common
5
+ doc 'Unprotect' do
6
+ desc 'Unprotects the given protected environment [Project ID, ProtectedEnvironment]'
7
+ example 'client.protected_environments.unprotect(264, :prod)'
8
+ end
9
+
10
+ doc 'Unprotect' do
11
+ desc 'via Project'
12
+ example <<~DOC
13
+ project = client.projects.show(264)
14
+ project.unprotect_environment(:other)
15
+ DOC
16
+ end
17
+
18
+ doc 'Unprotect' do
19
+ desc 'via ProtectedEnvironment'
20
+ example <<~DOC
21
+ protected_env = client.protected_environments.show(36, :prod)
22
+ protected_env.unprotect
23
+ DOC
24
+ end
25
+
26
+ def unprotect(project_id, environment_id)
27
+ project_id = format_id(project_id)
28
+ client.request(:delete, "projects/#{project_id}/protected_environments/#{environment_id}")
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,62 @@
1
+ # Top namespace
2
+ module LabClient
3
+ # Inspect Helper
4
+ class Membership < Klass
5
+ include ClassHelpers
6
+ include AccessLevel
7
+
8
+ def inspect
9
+ "#<Membership name: #{source_name}, access: #{level}>"
10
+ end
11
+
12
+ def parent
13
+ case source_type
14
+ when 'Project'
15
+ client.projects.show(source_id)
16
+ when 'Namespace'
17
+ client.groups.show(source_id)
18
+ end
19
+ end
20
+
21
+ def level
22
+ human_access_level(access_level)
23
+ end
24
+
25
+ def guest?
26
+ level == :guest
27
+ end
28
+
29
+ def reporter?
30
+ level == :reporter
31
+ end
32
+
33
+ def developer?
34
+ level == :developer
35
+ end
36
+
37
+ def maintainer?
38
+ level == :maintainer
39
+ end
40
+
41
+ def owner?
42
+ level == :owner
43
+ end
44
+
45
+ def greater_than(leveler)
46
+ case leveler
47
+ when Symbol
48
+ access_level > machine_access_level(leveler)
49
+ when Integer
50
+ access_level > leveler
51
+ end
52
+ end
53
+
54
+ help do
55
+ subtitle 'Membership'
56
+ option 'level', 'Humanized symbol of access level. e.g. :developer'
57
+ option 'parent', 'Collect project/namespace for this membership'
58
+ option '<permission>?', 'True/False evaluation each guest?, developer? etc'
59
+ option 'greater_than', 'True/False if user has greater than [Permission Name]'
60
+ end
61
+ end
62
+ end
@@ -7,7 +7,9 @@ module LabClient
7
7
  desc 'Lists all projects and groups a user is a member of. [User ID, Type]'
8
8
 
9
9
  markdown <<~DOC
10
- Filter memberships by type. Can be either Project or Namespace
10
+ | Attribute | Type | Required | Description |
11
+ | --------- | ------ | -------- | -------------------------------------------------------------- |
12
+ | type | string | no | Filter memberships by type. Can be either Project or Namespace |
11
13
  DOC
12
14
 
13
15
  example 'client.users.memberships(1)'
@@ -26,9 +28,12 @@ module LabClient
26
28
  DOC
27
29
  end
28
30
 
29
- def memberships(user_id, type = 'Project')
31
+ def memberships(user_id, type = nil)
30
32
  user_id = format_id(user_id)
31
- client.request(:get, "users/#{user_id}/memberships", nil, { from: type })
33
+
34
+ query = nil
35
+ query = { type: type } if type
36
+ client.request(:get, "users/#{user_id}/memberships", Membership, query)
32
37
  end
33
38
  end
34
39
  end
@@ -101,7 +101,7 @@ module LabClient
101
101
  client.impersonation_tokens.show(id, token_id)
102
102
  end
103
103
 
104
- def memberships(type = 'Project')
104
+ def memberships(type = nil)
105
105
  client.users.memberships(id, type)
106
106
  end
107
107
 
@@ -1,3 +1,3 @@
1
1
  module LabClient
2
- VERSION = '0.1.3'.freeze
2
+ VERSION = '0.1.4'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: labclient
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Davin Walker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-15 00:00:00.000000000 Z
11
+ date: 2020-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -766,6 +766,11 @@ files:
766
766
  - lib/labclient/protected_branches/protect.rb
767
767
  - lib/labclient/protected_branches/show.rb
768
768
  - lib/labclient/protected_branches/unprotect.rb
769
+ - lib/labclient/protected_environments/list.rb
770
+ - lib/labclient/protected_environments/protect.rb
771
+ - lib/labclient/protected_environments/protected_environment.rb
772
+ - lib/labclient/protected_environments/show.rb
773
+ - lib/labclient/protected_environments/unprotect.rb
769
774
  - lib/labclient/protected_tags/list.rb
770
775
  - lib/labclient/protected_tags/protect.rb
771
776
  - lib/labclient/protected_tags/show.rb
@@ -860,6 +865,7 @@ files:
860
865
  - lib/labclient/users/keys/list.rb
861
866
  - lib/labclient/users/keys/show.rb
862
867
  - lib/labclient/users/list.rb
868
+ - lib/labclient/users/membership.rb
863
869
  - lib/labclient/users/memberships.rb
864
870
  - lib/labclient/users/search.rb
865
871
  - lib/labclient/users/show.rb