uffizzi-cli 0.11.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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