uffizzi-cli 0.11.5 → 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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/config/uffizzi.rb +1 -0
  3. data/lib/uffizzi/cli/connect.rb +95 -46
  4. data/lib/uffizzi/cli/disconnect.rb +5 -2
  5. data/lib/uffizzi/cli/login.rb +11 -6
  6. data/lib/uffizzi/cli/login_by_identity_token.rb +47 -0
  7. data/lib/uffizzi/cli/preview.rb +95 -34
  8. data/lib/uffizzi/cli/project.rb +3 -1
  9. data/lib/uffizzi/cli.rb +8 -0
  10. data/lib/uffizzi/clients/api/api_client.rb +21 -14
  11. data/lib/uffizzi/clients/api/api_routes.rb +18 -8
  12. data/lib/uffizzi/clients/api/http_client.rb +4 -4
  13. data/lib/uffizzi/helpers/connect_helper.rb +45 -0
  14. data/lib/uffizzi/services/project_service.rb +1 -0
  15. data/lib/uffizzi/version.rb +1 -1
  16. data/man/uffizzi-connect +30 -31
  17. data/man/uffizzi-connect-acr +27 -25
  18. data/man/uffizzi-connect-acr.ronn +33 -19
  19. data/man/uffizzi-connect-docker-hub +24 -24
  20. data/man/uffizzi-connect-docker-hub.ronn +30 -18
  21. data/man/uffizzi-connect-docker-registry +37 -0
  22. data/man/uffizzi-connect-docker-registry.ronn +41 -0
  23. data/man/uffizzi-connect-ecr +27 -25
  24. data/man/uffizzi-connect-ecr.ronn +33 -19
  25. data/man/uffizzi-connect-gcr +20 -29
  26. data/man/uffizzi-connect-gcr.ronn +26 -22
  27. data/man/uffizzi-connect-ghcr +23 -33
  28. data/man/uffizzi-connect-ghcr.ronn +27 -23
  29. data/man/uffizzi-connect.ronn +28 -20
  30. data/man/uffizzi-login-by-identity-token +29 -0
  31. data/man/uffizzi-login-by-identity-token.html +106 -0
  32. data/man/uffizzi-login-by-identity-token.ronn +21 -0
  33. data/man/uffizzi-preview-create +16 -1
  34. data/man/uffizzi-preview-create.ronn +14 -0
  35. data/man/uffizzi-preview-list +25 -1
  36. data/man/uffizzi-preview-list.ronn +23 -0
  37. data/man/uffizzi-preview-update +20 -2
  38. data/man/uffizzi-preview-update.ronn +17 -0
  39. metadata +9 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a81fa2bb6f00491f6c59e4c10ea3ce067da1b75b26ff8543e1a08558893058c0
4
- data.tar.gz: fec82e0d04c499515f0221740a1a40b51bd5593a35223c0a7723648f20b25a5e
3
+ metadata.gz: ac2d58dae4db13ed788532732a92f9d4a317780cb4b80ef07d185f899d10749d
4
+ data.tar.gz: a1b4b37db41936eabb930febe701186027a80d0684ca371ed442168caecea779
5
5
  SHA512:
6
- metadata.gz: 82610a6fe745521646e7d7e7c5e0f65a39263ea53987f1e431d0a0d0b69033d015a67bcd48b07e30c5d044f2167c752f307525438ca232044e90c5b60eb0f602
7
- data.tar.gz: 67d5b6c3947e01e72c3ec678b6b14a1ccc6b78583d34f46274cdfa1f7692c9632b98728f43bf1ab5e0b3e984313db98e536c5231ddb9d2a07cc8156b8334ca2e
6
+ metadata.gz: c2420a93b4b17a5efb2de11ed5a998070da7eb2f8f22a2d09bf2598b4eb88841f428f0a87cf7de7c5b49e289f12f2d85413aa96600ca3726b71b5ec962e6b68c
7
+ data.tar.gz: 2dff8bd8e614d8ffaad6a2b42f528844c5a6d1232c2327bcb756c8ae6d4b014e3b310965f01fd86dc2d6eb40cb9aaab10755ef707a0dc808538620581b1f09cb
data/config/uffizzi.rb CHANGED
@@ -19,6 +19,7 @@ module Uffizzi
19
19
  google: 'UffizziCore::Credential::Google',
20
20
  amazon: 'UffizziCore::Credential::Amazon',
21
21
  github_registry: 'UffizziCore::Credential::GithubContainerRegistry',
22
+ docker_registry: 'UffizziCore::Credential::DockerRegistry',
22
23
  }
23
24
  config.default_server = 'app.uffizzi.com'
24
25
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'uffizzi'
4
+ require 'uffizzi/helpers/connect_helper'
4
5
 
5
6
  module Uffizzi
6
7
  class Cli::Connect < Thor
@@ -9,7 +10,8 @@ module Uffizzi
9
10
  desc 'list-credentials', 'List existing credentials for an account'
10
11
  def list_credentials
11
12
  server = ConfigFile.read_option(:server)
12
- response = fetch_credentials(server)
13
+ account_id = ConfigFile.read_option(:account_id)
14
+ response = fetch_credentials(server, account_id)
13
15
  if ResponseHelper.ok?(response)
14
16
  handle_list_credentials_success(response)
15
17
  else
@@ -21,42 +23,77 @@ module Uffizzi
21
23
  method_option :skip_raise_existence_error, type: :boolean, default: false,
22
24
  desc: 'Skip raising an error within check the credential'
23
25
  method_option :update_credential_if_exists, type: :boolean, default: false
26
+ method_option :username, type: :string, aliases: :u
27
+ method_option :password, type: :string, aliases: :p
24
28
  def docker_hub
25
29
  type = Uffizzi.configuration.credential_types[:dockerhub]
26
30
  credential_exists = credential_exists?(type)
27
31
  handle_existing_credential_options('docker-hub') if credential_exists
28
32
 
29
- username = ENV['DOCKERHUB_USERNAME'] || Uffizzi.ui.ask('Username:')
30
- password = ENV['DOCKERHUB_PASSWORD'] || Uffizzi.ui.ask('Password:', echo: false)
33
+ username, password = Uffizzi::ConnectHelper.get_docker_hub_data(options)
31
34
 
32
35
  params = {
33
36
  username: username,
34
37
  password: password,
35
38
  type: type,
36
39
  }
40
+ server = ConfigFile.read_option(:server)
41
+ account_id = ConfigFile.read_option(:account_id)
42
+
43
+ response = if credential_exists
44
+ update_credential(server, account_id, params, type)
45
+ else
46
+ create_credential(server, account_id, params)
47
+ end
48
+
49
+ handle_result_for('Docker Hub', response)
50
+ end
51
+
52
+ desc 'docker-registry', 'Connect to any registry implementing the Docker Registry HTTP API protocol'
53
+ method_option :skip_raise_existence_error, type: :boolean, default: false,
54
+ desc: 'Skip raising an error within check the credential'
55
+ method_option :update_credential_if_exists, type: :boolean, default: false
56
+ method_option :registry, type: :string, aliases: :r
57
+ method_option :username, type: :string, aliases: :u
58
+ method_option :password, type: :string, aliases: :p
59
+ def docker_registry
60
+ type = Uffizzi.configuration.credential_types[:docker_registry]
61
+ credential_exists = credential_exists?(type)
62
+ handle_existing_credential_options('docker-registry') if credential_exists
63
+
64
+ registry_url, username, password = Uffizzi::ConnectHelper.get_docker_registry_data(options)
37
65
 
66
+ params = {
67
+ registry_url: prepare_registry_url(registry_url),
68
+ username: username,
69
+ password: password,
70
+ type: type,
71
+ }
38
72
  server = ConfigFile.read_option(:server)
39
- response = create_or_update_credential(server, params, create: !credential_exists)
73
+ account_id = ConfigFile.read_option(:account_id)
40
74
 
41
- if successful?(response)
42
- print_success_message('Docker Hub')
75
+ response = if credential_exists
76
+ update_credential(server, account_id, params, type)
43
77
  else
44
- ResponseHelper.handle_failed_response(response)
78
+ create_credential(server, account_id, params)
45
79
  end
80
+
81
+ handle_result_for('Docker Registry', response)
46
82
  end
47
83
 
48
84
  desc 'acr', 'Connect to Azure Container Registry (azurecr.io)'
49
85
  method_option :skip_raise_existence_error, type: :boolean, default: false,
50
86
  desc: 'Skip raising an error within check the credential'
51
87
  method_option :update_credential_if_exists, type: :boolean, default: false
88
+ method_option :registry, type: :string, aliases: :r
89
+ method_option :username, type: :string, aliases: :u
90
+ method_option :password, type: :string, aliases: :p
52
91
  def acr
53
92
  type = Uffizzi.configuration.credential_types[:azure]
54
93
  credential_exists = credential_exists?(type)
55
94
  handle_existing_credential_options('acr') if credential_exists
56
95
 
57
- registry_url = ENV['ACR_REGISTRY_URL'] || Uffizzi.ui.ask('Registry Domain:')
58
- username = ENV['ACR_USERNAME'] || Uffizzi.ui.ask('Docker ID:')
59
- password = ENV['ACR_PASSWORD'] || Uffizzi.ui.ask('Password/Access Token:', echo: false)
96
+ registry_url, username, password = Uffizzi::ConnectHelper.get_acr_data(options)
60
97
 
61
98
  params = {
62
99
  username: username,
@@ -64,45 +101,48 @@ module Uffizzi
64
101
  registry_url: prepare_registry_url(registry_url),
65
102
  type: type,
66
103
  }
67
-
68
104
  server = ConfigFile.read_option(:server)
69
- response = create_or_update_credential(server, params, create: !credential_exists)
105
+ account_id = ConfigFile.read_option(:account_id)
70
106
 
71
- if successful?(response)
72
- print_success_message('ACR')
107
+ response = if credential_exists
108
+ update_credential(server, account_id, params, type)
73
109
  else
74
- ResponseHelper.handle_failed_response(response)
110
+ create_credential(server, account_id, params)
75
111
  end
112
+
113
+ handle_result_for('ACR', response)
76
114
  end
77
115
 
78
116
  desc 'ecr', 'Connect to Amazon Elastic Container Registry'
79
117
  method_option :skip_raise_existence_error, type: :boolean, default: false,
80
118
  desc: 'Skip raising an error within check the credential'
81
119
  method_option :update_credential_if_exists, type: :boolean, default: false
120
+ method_option :registry, type: :string, aliases: :r
121
+ method_option :id, type: :string
122
+ method_option :secret, type: :string, aliases: :s
82
123
  def ecr
83
124
  type = Uffizzi.configuration.credential_types[:amazon]
84
125
  credential_exists = credential_exists?(type)
85
126
  handle_existing_credential_options('ecr') if credential_exists
86
127
 
87
- registry_url = ENV['AWS_REGISTRY_URL'] || Uffizzi.ui.ask('Registry Domain:')
88
- access_key = ENV['AWS_ACCESS_KEY_ID'] || Uffizzi.ui.ask('Access key ID:')
89
- secret_access_key = ENV['AWS_SECRET_ACCESS_KEY'] || Uffizzi.ui.ask('Secret access key:', echo: false)
128
+ registry_url, access_key_id, secret_access_key = Uffizzi::ConnectHelper.get_ecr_data(options)
90
129
 
91
130
  params = {
92
- username: access_key,
131
+ username: access_key_id,
93
132
  password: secret_access_key,
94
133
  registry_url: prepare_registry_url(registry_url),
95
134
  type: type,
96
135
  }
97
-
98
136
  server = ConfigFile.read_option(:server)
99
- response = create_or_update_credential(server, params, create: !credential_exists)
137
+ account_id = ConfigFile.read_option(:account_id)
100
138
 
101
- if successful?(response)
102
- print_success_message('ECR')
139
+ response = if credential_exists
140
+ update_credential(server, account_id, params, type)
103
141
  else
104
- ResponseHelper.handle_failed_response(response)
142
+ create_credential(server, account_id, params)
105
143
  end
144
+
145
+ handle_result_for('ECR', response)
106
146
  end
107
147
 
108
148
  desc 'gcr', 'Connect to Google Container Registry (gcr.io)'
@@ -120,15 +160,16 @@ module Uffizzi
120
160
  password: credential_content,
121
161
  type: type,
122
162
  }
123
-
124
163
  server = ConfigFile.read_option(:server)
125
- response = create_or_update_credential(server, params, create: !credential_exists)
164
+ account_id = ConfigFile.read_option(:account_id)
126
165
 
127
- if successful?(response)
128
- print_success_message('GCR')
166
+ response = if credential_exists
167
+ update_credential(server, account_id, params, type)
129
168
  else
130
- ResponseHelper.handle_failed_response(response)
169
+ create_credential(server, account_id, params)
131
170
  end
171
+
172
+ handle_result_for('GCR', response)
132
173
  end
133
174
 
134
175
  desc 'ghcr', 'Connect to GitHub Container Registry (ghcr.io)'
@@ -142,32 +183,37 @@ module Uffizzi
142
183
  credential_exists = credential_exists?(type)
143
184
  handle_existing_credential_options('ghcr') if credential_exists
144
185
 
145
- username = options[:username] || ENV['GITHUB_USERNAME'] || Uffizzi.ui.ask('Github Username:')
146
- password = options[:token] || ENV['GITHUB_ACCESS_TOKEN'] || Uffizzi.ui.ask('Access Token:', echo: false)
186
+ username, password = Uffizzi::ConnectHelper.get_ghcr_data(options)
147
187
 
148
188
  params = {
149
189
  username: username,
150
190
  password: password,
151
191
  type: type,
152
192
  }
153
-
154
193
  server = ConfigFile.read_option(:server)
155
- response = create_or_update_credential(server, params, create: !credential_exists)
194
+ account_id = ConfigFile.read_option(:account_id)
156
195
 
157
- if successful?(response)
158
- print_success_message('GHCR')
196
+ response = if credential_exists
197
+ update_credential(server, account_id, params, type)
159
198
  else
160
- ResponseHelper.handle_failed_response(response)
199
+ create_credential(server, account_id, params)
161
200
  end
201
+
202
+ handle_result_for('GHCR', response)
162
203
  end
163
204
 
164
205
  map 'list-credentials' => 'list_credentials'
165
206
  map 'docker-hub' => 'docker_hub'
207
+ map 'docker-registry' => 'docker_registry'
166
208
 
167
209
  private
168
210
 
169
- def successful?(response)
170
- ResponseHelper.created?(response) || ResponseHelper.ok?(response)
211
+ def handle_result_for(credential_type, response)
212
+ if ResponseHelper.created?(response) || ResponseHelper.ok?(response)
213
+ print_success_message(credential_type)
214
+ else
215
+ ResponseHelper.handle_failed_response(response)
216
+ end
171
217
  end
172
218
 
173
219
  def prepare_registry_url(registry_url)
@@ -176,14 +222,21 @@ module Uffizzi
176
222
  "https://#{registry_url}"
177
223
  end
178
224
 
179
- def print_success_message(credential_type_slug)
180
- Uffizzi.ui.say("Successfully connected to #{credential_type_slug}.")
225
+ def print_success_message(credential_type)
226
+ Uffizzi.ui.say("Successfully connected to #{credential_type}.")
181
227
  end
182
228
 
183
229
  def credential_exists?(type)
184
230
  server = ConfigFile.read_option(:server)
185
- response = check_credential(server, type)
186
- !ResponseHelper.ok?(response)
231
+ account_id = ConfigFile.read_option(:account_id)
232
+ response = check_credential(server, account_id, type)
233
+ return false if ResponseHelper.ok?(response)
234
+ return true if ResponseHelper.unprocessable_entity?(response)
235
+
236
+ if ResponseHelper.forbidden?(response)
237
+ Uffizzi.ui.say('Unauthorized. Skipping credentials action.')
238
+ exit(true)
239
+ end
187
240
  end
188
241
 
189
242
  def handle_existing_credential_options(credential_type_slug)
@@ -202,10 +255,6 @@ module Uffizzi
202
255
  end
203
256
  end
204
257
 
205
- def create_or_update_credential(server, params, create: true)
206
- create ? create_credential(server, params) : update_credential(server, params, params[:type])
207
- end
208
-
209
258
  def handle_list_credentials_success(response)
210
259
  credentials = response[:body][:credentials]
211
260
  credentials.each do |credential|
@@ -10,6 +10,8 @@ module Uffizzi
10
10
  connection_type = case credential_type
11
11
  when 'docker-hub'
12
12
  Uffizzi.configuration.credential_types[:dockerhub]
13
+ when 'docker-registry'
14
+ Uffizzi.configuration.credential_types[:docker_registry]
13
15
  when 'acr'
14
16
  Uffizzi.configuration.credential_types[:azure]
15
17
  when 'ecr'
@@ -22,10 +24,10 @@ module Uffizzi
22
24
  raise Uffizzi::Error.new('Unsupported credential type.')
23
25
  end
24
26
 
25
- response = delete_credential(ConfigFile.read_option(:server), connection_type)
27
+ response = delete_credential(ConfigFile.read_option(:server), ConfigFile.read_option(:account_id), connection_type)
26
28
 
27
29
  if ResponseHelper.no_content?(response)
28
- Uffizzi.ui.say("Successfully disconnected #{connection_name(credential_type)} connection")
30
+ Uffizzi.ui.say("Successfully disconnected from #{connection_name(credential_type)}.")
29
31
  else
30
32
  ResponseHelper.handle_failed_response(response)
31
33
  end
@@ -36,6 +38,7 @@ module Uffizzi
36
38
  def connection_name(credential_type)
37
39
  {
38
40
  'docker-hub' => 'DockerHub',
41
+ 'docker-registry' => 'Docker Registry',
39
42
  'acr' => 'ACR',
40
43
  'ecr' => 'ECR',
41
44
  'gcr' => 'GCR',
@@ -34,17 +34,17 @@ module Uffizzi
34
34
 
35
35
  def set_server
36
36
  config_server = ConfigFile.exists? ? read_option_from_config(:server) : nil
37
- server_address = @options[:server] || config_server || Uffizzi.ui.ask('Server: ')
37
+ server_address = (@options[:server] || config_server || Uffizzi.ui.ask('Server:')).sub(/\/+$/, '')
38
38
  server_address.start_with?('http:', 'https:') ? server_address : "https://#{server_address}"
39
39
  end
40
40
 
41
41
  def set_username
42
42
  config_username = ConfigFile.exists? ? read_option_from_config(:username) : nil
43
- @options[:username] || config_username || Uffizzi.ui.ask('Username: ')
43
+ @options[:username] || config_username || Uffizzi.ui.ask('Username:')
44
44
  end
45
45
 
46
46
  def set_password
47
- ENV['UFFIZZI_PASSWORD'] || Uffizzi.ui.ask('Password: ', echo: false)
47
+ ENV['UFFIZZI_PASSWORD'] || Uffizzi.ui.ask('Password:', echo: false)
48
48
  end
49
49
 
50
50
  def read_option_from_config(option)
@@ -61,6 +61,7 @@ module Uffizzi
61
61
  end
62
62
 
63
63
  def handle_succeed_response(response, server, username)
64
+ # TODO Choose a personal account
64
65
  account = response[:body][:user][:accounts].first
65
66
  return Uffizzi.ui.say('No account related to this email') unless account_valid?(account)
66
67
 
@@ -95,9 +96,11 @@ module Uffizzi
95
96
  end
96
97
  all_choices = choices + [{ name: 'Create a new project', value: nil }]
97
98
  answer = Uffizzi.prompt.select(question, all_choices)
98
- return ConfigFile.write_option(:project, answer) if answer
99
+ return create_new_project(server) unless answer
99
100
 
100
- create_new_project(server)
101
+ account_id = projects.detect { |project| project[:slug] == answer }[:account_id]
102
+ ConfigFile.write_option(:project, answer)
103
+ ConfigFile.write_option(:account_id, account_id)
101
104
  end
102
105
 
103
106
  def create_new_project(server)
@@ -116,7 +119,8 @@ module Uffizzi
116
119
  },
117
120
  }
118
121
 
119
- response = create_project(server, params)
122
+ account_id = ConfigFile.read_option(:account_id)
123
+ response = create_project(server, account_id, params)
120
124
 
121
125
  if ResponseHelper.created?(response)
122
126
  handle_create_project_succeess(response)
@@ -139,6 +143,7 @@ module Uffizzi
139
143
  project = response[:body][:project]
140
144
 
141
145
  ConfigFile.write_option(:project, project[:slug])
146
+ ConfigFile.write_option(:account_id, project[:account_id])
142
147
 
143
148
  Uffizzi.ui.say("Project #{project[:name]} was successfully created")
144
149
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uffizzi'
4
+ require 'uffizzi/response_helper'
5
+ require 'uffizzi/clients/api/api_client'
6
+
7
+ module Uffizzi
8
+ class Cli::LoginByIdentityToken
9
+ include ApiClient
10
+
11
+ def initialize(options)
12
+ @options = options
13
+ end
14
+
15
+ def run
16
+ token = @options[:token]
17
+ server = @options[:server]
18
+ params = prepare_request_params(token)
19
+ response = create_ci_session(server, params)
20
+
21
+ if ResponseHelper.created?(response)
22
+ handle_succeed_response(response, server)
23
+ else
24
+ ResponseHelper.handle_failed_response(response)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def prepare_request_params(token)
31
+ {
32
+ user: {
33
+ token: token,
34
+ },
35
+ }
36
+ end
37
+
38
+ def handle_succeed_response(response, server)
39
+ ConfigFile.write_option(:server, server)
40
+ ConfigFile.write_option(:cookie, response[:headers])
41
+ ConfigFile.write_option(:account_id, response[:body][:account_id])
42
+ ConfigFile.write_option(:project, response[:body][:project_slug])
43
+
44
+ Uffizzi.ui.say('Successful Login by Identity Token')
45
+ end
46
+ end
47
+ end
@@ -12,19 +12,24 @@ module Uffizzi
12
12
  desc 'service', 'Show the preview services info'
13
13
  require_relative 'preview/service'
14
14
  subcommand 'service', Uffizzi::Cli::Preview::Service
15
+
15
16
  desc 'list', 'List all previews'
17
+ method_option :filter, required: false, type: :string, aliases: '-f'
18
+ method_option :output, required: false, type: :string, aliases: '-o', enum: ['json']
16
19
  def list
17
20
  run('list')
18
21
  end
19
22
 
20
23
  desc 'create [COMPOSE_FILE]', 'Create a preview'
21
24
  method_option :output, required: false, type: :string, aliases: '-o', enum: ['json', 'github-action']
25
+ method_option :"set-labels", required: false, type: :string, aliases: '-s'
22
26
  def create(file_path = nil)
23
27
  run('create', file_path: file_path)
24
28
  end
25
29
 
26
30
  desc 'uffizzi preview update [DEPLOYMENT_ID] [COMPOSE_FILE]', 'Update a preview'
27
31
  method_option :output, required: false, type: :string, aliases: '-o', enum: ['json', 'github-action']
32
+ method_option :"set-labels", required: false, type: :string, aliases: '-s'
28
33
  def update(deployment_name, file_path)
29
34
  run('update', deployment_name: deployment_name, file_path: file_path)
30
35
  end
@@ -47,10 +52,7 @@ module Uffizzi
47
52
  private
48
53
 
49
54
  def run(command, file_path: nil, deployment_name: nil)
50
- unless options[:output].nil?
51
- Uffizzi.ui.output_format = options[:output]
52
- Uffizzi.ui.disable_stdout
53
- end
55
+ Uffizzi.ui.output_format = options[:output]
54
56
  raise Uffizzi::Error.new('You are not logged in.') unless Uffizzi::AuthHelper.signed_in?
55
57
  raise Uffizzi::Error.new('This command needs project to be set in config file') unless CommandService.project_set?(options)
56
58
 
@@ -58,11 +60,11 @@ module Uffizzi
58
60
 
59
61
  case command
60
62
  when 'list'
61
- handle_list_command(project_slug)
63
+ handle_list_command(project_slug, options[:filter])
62
64
  when 'create'
63
- handle_create_command(file_path, project_slug)
65
+ handle_create_command(file_path, project_slug, options[:"set-labels"])
64
66
  when 'update'
65
- handle_update_command(deployment_name, file_path, project_slug)
67
+ handle_update_command(deployment_name, file_path, project_slug, options[:"set-labels"])
66
68
  when 'delete'
67
69
  handle_delete_command(deployment_name, project_slug)
68
70
  when 'describe'
@@ -72,8 +74,9 @@ module Uffizzi
72
74
  end
73
75
  end
74
76
 
75
- def handle_list_command(project_slug)
76
- response = fetch_deployments(ConfigFile.read_option(:server), project_slug)
77
+ def handle_list_command(project_slug, filter)
78
+ parsed_filter = filter.nil? ? {} : build_filter_params(filter)
79
+ response = fetch_deployments(ConfigFile.read_option(:server), project_slug, parsed_filter)
77
80
 
78
81
  if ResponseHelper.ok?(response)
79
82
  handle_succeed_list_response(response)
@@ -82,8 +85,10 @@ module Uffizzi
82
85
  end
83
86
  end
84
87
 
85
- def handle_create_command(file_path, project_slug)
86
- params = file_path.nil? ? {} : prepare_params(file_path)
88
+ def handle_create_command(file_path, project_slug, labels)
89
+ Uffizzi.ui.disable_stdout unless options[:output].nil?
90
+ params = prepare_params(file_path, labels)
91
+
87
92
  response = create_deployment(ConfigFile.read_option(:server), project_slug, params)
88
93
 
89
94
  if !ResponseHelper.created?(response)
@@ -101,12 +106,13 @@ module Uffizzi
101
106
  handle_preview_interruption(deployment_id, ConfigFile.read_option(:server), project_slug)
102
107
  end
103
108
 
104
- def handle_update_command(deployment_name, file_path, project_slug)
109
+ def handle_update_command(deployment_name, file_path, project_slug, labels)
110
+ Uffizzi.ui.disable_stdout unless options[:output].nil?
105
111
  deployment_id = PreviewService.read_deployment_id(deployment_name)
106
112
 
107
113
  raise Uffizzi::Error.new("Preview should be specified in 'deployment-PREVIEW_ID' format") if deployment_id.nil?
108
114
 
109
- params = prepare_params(file_path)
115
+ params = prepare_params(file_path, labels)
110
116
  response = update_deployment(ConfigFile.read_option(:server), project_slug, deployment_id, params)
111
117
 
112
118
  if !ResponseHelper.ok?(response)
@@ -175,7 +181,11 @@ module Uffizzi
175
181
  raise Uffizzi::Error.new('The project has no active deployments') if deployments.empty?
176
182
 
177
183
  deployments.each do |deployment|
178
- Uffizzi.ui.say("deployment-#{deployment[:id]}")
184
+ if Uffizzi.ui.output_format.nil?
185
+ Uffizzi.ui.say("deployment-#{deployment[:id]}")
186
+ else
187
+ Uffizzi.ui.pretty_say(deployment)
188
+ end
179
189
  end
180
190
  end
181
191
 
@@ -205,26 +215,10 @@ module Uffizzi
205
215
  end
206
216
  end
207
217
 
208
- def prepare_params(file_path)
209
- begin
210
- compose_file_data = EnvVariablesService.substitute_env_variables(File.read(file_path))
211
- rescue Errno::ENOENT => e
212
- raise Uffizzi::Error.new(e.message)
213
- end
214
-
215
- compose_file_dir = File.dirname(file_path)
216
- dependencies = ComposeFileService.parse(compose_file_data, compose_file_dir)
217
- absolute_path = File.absolute_path(file_path)
218
- compose_file_params = {
219
- path: absolute_path,
220
- content: Base64.encode64(compose_file_data),
221
- source: absolute_path,
222
- }
223
-
224
- {
225
- compose_file: compose_file_params,
226
- dependencies: dependencies,
227
- }
218
+ def prepare_params(file_path, labels)
219
+ compose_file_params = file_path.nil? ? {} : build_compose_file_params(file_path)
220
+ metadata_params = labels.nil? ? {} : build_metadata_params(labels)
221
+ compose_file_params.merge(metadata_params)
228
222
  end
229
223
 
230
224
  def handle_preview_interruption(deployment_id, server, project_slug)
@@ -251,10 +245,77 @@ module Uffizzi
251
245
  end
252
246
 
253
247
  def build_deployment_data(deployment)
248
+ url_server = ConfigFile.read_option(:server)
249
+
254
250
  {
255
251
  id: "deployment-#{deployment[:id]}",
256
252
  url: "https://#{deployment[:preview_url]}",
253
+ containers_uri: "#{url_server}/projects/#{deployment[:project_id]}/deployments/#{deployment[:id]}/containers",
257
254
  }
258
255
  end
256
+
257
+ def build_compose_file_params(file_path)
258
+ begin
259
+ compose_file_data = EnvVariablesService.substitute_env_variables(File.read(file_path))
260
+ rescue Errno::ENOENT => e
261
+ raise Uffizzi::Error.new(e.message)
262
+ end
263
+
264
+ compose_file_dir = File.dirname(file_path)
265
+ dependencies = ComposeFileService.parse(compose_file_data, compose_file_dir)
266
+ absolute_path = File.absolute_path(file_path)
267
+ compose_file_params = {
268
+ path: absolute_path,
269
+ content: Base64.encode64(compose_file_data),
270
+ source: absolute_path,
271
+ }
272
+
273
+ {
274
+ compose_file: compose_file_params,
275
+ dependencies: dependencies,
276
+ }
277
+ end
278
+
279
+ def build_metadata_params(labels)
280
+ {
281
+ metadata: {
282
+ 'labels' => parse_params(labels, 'Labels'),
283
+ },
284
+ }
285
+ end
286
+
287
+ def build_filter_params(filter_params)
288
+ {
289
+ 'labels' => parse_params(filter_params, 'Filtering parameters'),
290
+ }
291
+ end
292
+
293
+ def parse_params(params, params_type)
294
+ validate_params(params, params_type)
295
+ params.split(' ').reduce({}) do |acc, param|
296
+ stringified_keys, value = param.split('=', 2)
297
+ keys = stringified_keys.split('.', -1)
298
+ inner_pair = { keys.pop => value }
299
+ prepared_param = keys.reverse.reduce(inner_pair) { |res, key| { key => res } }
300
+ merge_params(acc, prepared_param)
301
+ end
302
+ end
303
+
304
+ def validate_params(params, params_type)
305
+ params.split(' ').each do |param|
306
+ stringified_keys, value = param.split('=', 2)
307
+ raise Uffizzi::Error.new("#{params_type} were set in incorrect format.") if value.nil? || stringified_keys.nil? || value.empty?
308
+
309
+ keys = stringified_keys.split('.', -1)
310
+ raise Uffizzi::Error.new("#{params_type} were set in incorrect format.") if keys.empty? || keys.any?(&:empty?)
311
+ end
312
+ end
313
+
314
+ def merge_params(result, param)
315
+ key = param.keys.first
316
+ return result.merge(param) unless result.has_key?(key)
317
+
318
+ { key => result[key].merge(merge_params(result[key], param[key])) }
319
+ end
259
320
  end
260
321
  end
@@ -102,12 +102,13 @@ module Uffizzi
102
102
  raise Uffizzi::Error.new('Slug must not content spaces or special characters') unless slug.match?(/^[a-zA-Z0-9\-_]+\Z/i)
103
103
 
104
104
  server = ConfigFile.read_option(:server)
105
+ account_id = ConfigFile.read_option(:account_id)
105
106
  params = {
106
107
  name: name,
107
108
  description: options[:description],
108
109
  slug: slug,
109
110
  }
110
- response = create_project(server, params)
111
+ response = create_project(server, account_id, params)
111
112
 
112
113
  if ResponseHelper.created?(response)
113
114
  handle_create_success_response(response)
@@ -165,6 +166,7 @@ module Uffizzi
165
166
 
166
167
  def set_default_project(project)
167
168
  ConfigFile.write_option(:project, project[:slug])
169
+ ConfigFile.write_option(:account_id, project[:account_id])
168
170
  end
169
171
  end
170
172
  end