uffizzi-cli 0.8.0 → 0.10.1
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/config/uffizzi.rb +1 -1
- data/lib/uffizzi/auth_helper.rb +5 -0
- data/lib/uffizzi/cli/config.rb +1 -1
- data/lib/uffizzi/cli/connect.rb +54 -31
- data/lib/uffizzi/cli/disconnect.rb +1 -1
- data/lib/uffizzi/cli/login.rb +76 -2
- data/lib/uffizzi/cli/logout.rb +1 -1
- data/lib/uffizzi/cli/preview.rb +4 -1
- data/lib/uffizzi/cli/project.rb +82 -2
- data/lib/uffizzi/cli.rb +3 -1
- data/lib/uffizzi/clients/api/api_client.rb +15 -1
- data/lib/uffizzi/config_file.rb +8 -18
- data/lib/uffizzi/helpers/project_helper.rb +22 -0
- data/lib/uffizzi/promt.rb +21 -0
- data/lib/uffizzi/services/project_service.rb +40 -0
- data/lib/uffizzi/version.rb +1 -1
- data/lib/uffizzi.rb +5 -0
- data/man/uffizzi +2 -2
- data/man/uffizzi-config +2 -2
- data/man/uffizzi-config.ronn +1 -1
- data/man/uffizzi-connect +2 -2
- data/man/uffizzi-connect-acr +2 -2
- data/man/uffizzi-connect-acr.ronn +1 -1
- data/man/uffizzi-connect-docker-hub +2 -2
- data/man/uffizzi-connect-docker-hub.ronn +1 -1
- data/man/uffizzi-connect-ecr +2 -2
- data/man/uffizzi-connect-ecr.ronn +1 -1
- data/man/uffizzi-connect-gcr +2 -2
- data/man/uffizzi-connect-gcr.ronn +1 -1
- data/man/uffizzi-connect-ghcr +2 -2
- data/man/uffizzi-connect-ghcr.ronn +1 -1
- data/man/uffizzi-connect.ronn +1 -1
- data/man/uffizzi-disconnect +2 -2
- data/man/uffizzi-disconnect.ronn +1 -1
- data/man/uffizzi-login +2 -2
- data/man/uffizzi-login.ronn +1 -1
- data/man/uffizzi-logout +2 -2
- data/man/uffizzi-logout.ronn +1 -1
- data/man/uffizzi-preview +2 -2
- data/man/uffizzi-preview-create +2 -2
- data/man/uffizzi-preview-create.ronn +1 -1
- data/man/uffizzi-preview-delete +2 -2
- data/man/uffizzi-preview-delete.ronn +1 -1
- data/man/uffizzi-preview-describe +2 -2
- data/man/uffizzi-preview-describe.ronn +1 -1
- data/man/uffizzi-preview-events +2 -2
- data/man/uffizzi-preview-events.ronn +1 -1
- data/man/uffizzi-preview-list +2 -2
- data/man/uffizzi-preview-list.ronn +1 -1
- data/man/uffizzi-preview-service-list +2 -2
- data/man/uffizzi-preview-service-list.ronn +1 -1
- data/man/uffizzi-preview-service-logs +2 -2
- data/man/uffizzi-preview-service-logs.ronn +1 -1
- data/man/uffizzi-preview-update +20 -12
- data/man/uffizzi-preview-update.ronn +6 -6
- data/man/uffizzi-preview.ronn +1 -1
- data/man/uffizzi-preview_service_logs +2 -2
- data/man/uffizzi-preview_service_logs.ronn +1 -1
- data/man/uffizzi-project +2 -2
- data/man/uffizzi-project-compose +2 -2
- data/man/uffizzi-project-compose-describe +2 -2
- data/man/uffizzi-project-compose-describe.ronn +1 -1
- data/man/uffizzi-project-compose-set +2 -2
- data/man/uffizzi-project-compose-set.ronn +1 -1
- data/man/uffizzi-project-compose-unset +2 -2
- data/man/uffizzi-project-compose-unset.ronn +1 -1
- data/man/uffizzi-project-compose.ronn +1 -1
- data/man/uffizzi-project-create +50 -0
- data/man/uffizzi-project-create.ronn +41 -0
- data/man/uffizzi-project-delete +32 -0
- data/man/uffizzi-project-delete.ronn +24 -0
- data/man/uffizzi-project-describe +43 -0
- data/man/uffizzi-project-describe.ronn +34 -0
- data/man/uffizzi-project-secret +2 -2
- data/man/uffizzi-project-secret-create +2 -2
- data/man/uffizzi-project-secret-create.ronn +1 -1
- data/man/uffizzi-project-secret-delete +2 -2
- data/man/uffizzi-project-secret-delete.ronn +1 -1
- data/man/uffizzi-project-secret-list +2 -2
- data/man/uffizzi-project-secret-list.ronn +1 -1
- data/man/uffizzi-project-secret.ronn +1 -1
- data/man/uffizzi-project-set-default +2 -2
- data/man/uffizzi-project-set-default.ronn +1 -1
- data/man/uffizzi-project.ronn +1 -1
- data/man/uffizzi.html +1 -1
- data/man/uffizzi.ronn +1 -1
- metadata +25 -22
- data/man/uffizzi-config.html +0 -144
- data/man/uffizzi-login.html +0 -113
- data/man/uffizzi-logout.html +0 -102
- data/man/uffizzi-preview-create.html +0 -128
- data/man/uffizzi-preview-delete.html +0 -115
- data/man/uffizzi-preview-describe.html +0 -116
- data/man/uffizzi-preview-events.html +0 -110
- data/man/uffizzi-preview-list.html +0 -110
- data/man/uffizzi-preview.html +0 -120
- data/man/uffizzi-preview_service_logs.html +0 -142
- data/man/uffizzi-project-compose-describe.html +0 -118
- data/man/uffizzi-project-compose-set.html +0 -149
- data/man/uffizzi-project-compose-unset.html +0 -116
- data/man/uffizzi-project-compose.html +0 -123
- data/man/uffizzi-project-secret-create.html +0 -110
- data/man/uffizzi-project-secret-delete.html +0 -110
- data/man/uffizzi-project-secret-list.html +0 -110
- data/man/uffizzi-project-secret.html +0 -119
- data/man/uffizzi-project-set-default.html +0 -111
- data/man/uffizzi-project.html +0 -128
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aad4e300e1250ee113d65b436b58045b368c707c5840bc26375918a33c894a5a
|
|
4
|
+
data.tar.gz: 711dc99c47c9d073405da14ce9409e2bfe99eaca6028143da0eccb7961ba8426
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aebda9657557027599278995e7a97bef373b118cdf4a8055d17706f418ffbd7b6a126703dfa5901833ab2c7198f91d91c5f07da5c836b0b602382a6fe860c235
|
|
7
|
+
data.tar.gz: 951c78b92cbee8f70a5b41231fa56cd9ea0cf3ec278c174b703a065567eb1d4ddfca18484396c5db208ea85d6fd1ad8f59c8c9a8a8c29ebbbc5fbe8b308e0ff8
|
data/config/uffizzi.rb
CHANGED
|
@@ -18,7 +18,7 @@ module Uffizzi
|
|
|
18
18
|
azure: 'UffizziCore::Credential::Azure',
|
|
19
19
|
google: 'UffizziCore::Credential::Google',
|
|
20
20
|
amazon: 'UffizziCore::Credential::Amazon',
|
|
21
|
-
|
|
21
|
+
github_registry: 'UffizziCore::Credential::GithubContainerRegistry',
|
|
22
22
|
}
|
|
23
23
|
config.default_server = 'app.uffizzi.com'
|
|
24
24
|
end
|
data/lib/uffizzi/auth_helper.rb
CHANGED
data/lib/uffizzi/cli/config.rb
CHANGED
|
@@ -58,7 +58,7 @@ module Uffizzi
|
|
|
58
58
|
\nUffizzi API service and manage previews.\n")
|
|
59
59
|
server = Uffizzi.ui.ask('Server: ', default: Uffizzi.configuration.default_server.to_s)
|
|
60
60
|
username = Uffizzi.ui.ask('Username: ')
|
|
61
|
-
project = Uffizzi.ui.ask('Project: ')
|
|
61
|
+
project = Uffizzi.ui.ask('Project: ', default: 'default')
|
|
62
62
|
ConfigFile.delete
|
|
63
63
|
ConfigFile.write_option(:server, server)
|
|
64
64
|
ConfigFile.write_option(:username, username)
|
data/lib/uffizzi/cli/connect.rb
CHANGED
|
@@ -18,12 +18,14 @@ module Uffizzi
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
desc 'docker-hub', 'Connect to Docker Hub (hub.docker.com)'
|
|
21
|
+
method_option :skip_raise_existence_error, type: :boolean, default: false,
|
|
22
|
+
desc: 'Skip raising an error within check the credential'
|
|
21
23
|
def docker_hub
|
|
22
24
|
type = Uffizzi.configuration.credential_types[:dockerhub]
|
|
23
|
-
|
|
25
|
+
check_credential_existence(type, 'docker-hub')
|
|
24
26
|
|
|
25
|
-
username = Uffizzi.ui.ask('Username: ')
|
|
26
|
-
password = Uffizzi.ui.ask('Password: ', echo: false)
|
|
27
|
+
username = ENV['DOCKERHUB_USERNAME'] || Uffizzi.ui.ask('Username: ')
|
|
28
|
+
password = ENV['DOCKERHUB_PASSWORD'] || Uffizzi.ui.ask('Password: ', echo: false)
|
|
27
29
|
|
|
28
30
|
params = {
|
|
29
31
|
username: username,
|
|
@@ -42,18 +44,20 @@ module Uffizzi
|
|
|
42
44
|
end
|
|
43
45
|
|
|
44
46
|
desc 'acr', 'Connect to Azure Container Registry (azurecr.io)'
|
|
47
|
+
method_option :skip_raise_existence_error, type: :boolean, default: false,
|
|
48
|
+
desc: 'Skip raising an error within check the credential'
|
|
45
49
|
def acr
|
|
46
50
|
type = Uffizzi.configuration.credential_types[:azure]
|
|
47
|
-
|
|
51
|
+
check_credential_existence(type, 'acr')
|
|
48
52
|
|
|
49
|
-
registry_url =
|
|
50
|
-
username = Uffizzi.ui.ask('Docker ID: ')
|
|
51
|
-
password = Uffizzi.ui.ask('Password/Access Token: ', echo: false)
|
|
53
|
+
registry_url = ENV['ACR_REGISTRY_URL'] || Uffizzi.ui.ask('Registry Domain: ')
|
|
54
|
+
username = ENV['ACR_USERNAME'] || Uffizzi.ui.ask('Docker ID: ')
|
|
55
|
+
password = ENV['ACR_PASSWORD'] || Uffizzi.ui.ask('Password/Access Token: ', echo: false)
|
|
52
56
|
|
|
53
57
|
params = {
|
|
54
58
|
username: username,
|
|
55
59
|
password: password,
|
|
56
|
-
registry_url: registry_url,
|
|
60
|
+
registry_url: prepare_registry_url(registry_url),
|
|
57
61
|
type: type,
|
|
58
62
|
}
|
|
59
63
|
|
|
@@ -68,18 +72,20 @@ module Uffizzi
|
|
|
68
72
|
end
|
|
69
73
|
|
|
70
74
|
desc 'ecr', 'Connect to Amazon Elastic Container Registry'
|
|
75
|
+
method_option :skip_raise_existence_error, type: :boolean, default: false,
|
|
76
|
+
desc: 'Skip raising an error within check the credential'
|
|
71
77
|
def ecr
|
|
72
78
|
type = Uffizzi.configuration.credential_types[:amazon]
|
|
73
|
-
|
|
79
|
+
check_credential_existence(type, 'ecr')
|
|
74
80
|
|
|
75
|
-
registry_url =
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
registry_url = ENV['AWS_REGISTRY_URL'] || Uffizzi.ui.ask('Registry Domain: ')
|
|
82
|
+
access_key = ENV['AWS_ACCESS_KEY_ID'] || Uffizzi.ui.ask('Access key ID: ')
|
|
83
|
+
secret_access_key = ENV['AWS_SECRET_ACCESS_KEY'] || Uffizzi.ui.ask('Secret access key: ', echo: false)
|
|
78
84
|
|
|
79
85
|
params = {
|
|
80
|
-
username:
|
|
81
|
-
password:
|
|
82
|
-
registry_url: registry_url,
|
|
86
|
+
username: access_key,
|
|
87
|
+
password: secret_access_key,
|
|
88
|
+
registry_url: prepare_registry_url(registry_url),
|
|
83
89
|
type: type,
|
|
84
90
|
}
|
|
85
91
|
|
|
@@ -94,17 +100,13 @@ module Uffizzi
|
|
|
94
100
|
end
|
|
95
101
|
|
|
96
102
|
desc 'gcr', 'Connect to Google Container Registry (gcr.io)'
|
|
103
|
+
method_option :skip_raise_existence_error, type: :boolean, default: false,
|
|
104
|
+
desc: 'Skip raising an error within check the credential'
|
|
97
105
|
def gcr(credential_file_path = nil)
|
|
98
106
|
type = Uffizzi.configuration.credential_types[:google]
|
|
99
|
-
|
|
107
|
+
check_credential_existence(type, 'gcr')
|
|
100
108
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
begin
|
|
104
|
-
credential_content = File.read(credential_file_path)
|
|
105
|
-
rescue Errno::ENOENT => e
|
|
106
|
-
return Uffizzi.ui.say(e)
|
|
107
|
-
end
|
|
109
|
+
credential_content = google_service_account_content(credential_file_path)
|
|
108
110
|
|
|
109
111
|
params = {
|
|
110
112
|
password: credential_content,
|
|
@@ -122,12 +124,14 @@ module Uffizzi
|
|
|
122
124
|
end
|
|
123
125
|
|
|
124
126
|
desc 'ghcr', 'Connect to GitHub Container Registry (ghcr.io)'
|
|
127
|
+
method_option :skip_raise_existence_error, type: :boolean, default: false,
|
|
128
|
+
desc: 'Skip raising an error within check the credential'
|
|
125
129
|
def ghcr
|
|
126
|
-
type = Uffizzi.configuration.credential_types[:
|
|
127
|
-
|
|
130
|
+
type = Uffizzi.configuration.credential_types[:github_registry]
|
|
131
|
+
check_credential_existence(type, 'ghcr')
|
|
128
132
|
|
|
129
|
-
username = Uffizzi.ui.ask('Github Username: ')
|
|
130
|
-
password = Uffizzi.ui.ask('Access Token: ', echo: false)
|
|
133
|
+
username = ENV['GITHUB_USERNAME'] || Uffizzi.ui.ask('Github Username: ')
|
|
134
|
+
password = ENV['GITHUB_ACCESS_TOKEN'] || Uffizzi.ui.ask('Access Token: ', echo: false)
|
|
131
135
|
|
|
132
136
|
params = {
|
|
133
137
|
username: username,
|
|
@@ -160,14 +164,19 @@ module Uffizzi
|
|
|
160
164
|
Uffizzi.ui.say("Successfully connected to #{connection_name}")
|
|
161
165
|
end
|
|
162
166
|
|
|
163
|
-
def
|
|
167
|
+
def check_credential_existence(type, connection_name)
|
|
164
168
|
server = ConfigFile.read_option(:server)
|
|
165
169
|
response = check_credential(server, type)
|
|
166
170
|
return if ResponseHelper.ok?(response)
|
|
167
171
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
172
|
+
if options.skip_raise_existence_error?
|
|
173
|
+
Uffizzi.ui.say("Credentials of type #{connection_name} already exist for this account.")
|
|
174
|
+
exit(true)
|
|
175
|
+
else
|
|
176
|
+
message = "Credentials of type #{connection_name} already exist for this account. " \
|
|
177
|
+
"To remove them, run $ uffizzi disconnect #{connection_name}."
|
|
178
|
+
raise Uffizzi::Error.new(message)
|
|
179
|
+
end
|
|
171
180
|
end
|
|
172
181
|
|
|
173
182
|
def handle_list_credentials_success(response)
|
|
@@ -189,5 +198,19 @@ module Uffizzi
|
|
|
189
198
|
|
|
190
199
|
map[credential]
|
|
191
200
|
end
|
|
201
|
+
|
|
202
|
+
def google_service_account_content(credential_file_path = nil)
|
|
203
|
+
return ENV['GCLOUD_SERVICE_KEY'] if ENV['GCLOUD_SERVICE_KEY']
|
|
204
|
+
|
|
205
|
+
return Uffizzi.ui.say('Path to google service account key file wasn\'t specified.') if credential_file_path.nil?
|
|
206
|
+
|
|
207
|
+
begin
|
|
208
|
+
credential_content = File.read(credential_file_path)
|
|
209
|
+
rescue Errno::ENOENT => e
|
|
210
|
+
raise Uffizzi::Error.new(e.message)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
credential_content
|
|
214
|
+
end
|
|
192
215
|
end
|
|
193
216
|
end
|
|
@@ -17,7 +17,7 @@ module Uffizzi
|
|
|
17
17
|
when 'gcr'
|
|
18
18
|
Uffizzi.configuration.credential_types[:google]
|
|
19
19
|
when 'ghcr'
|
|
20
|
-
Uffizzi.configuration.credential_types[:
|
|
20
|
+
Uffizzi.configuration.credential_types[:github_registry]
|
|
21
21
|
else
|
|
22
22
|
raise Uffizzi::Error.new('Unsupported credential type.')
|
|
23
23
|
end
|
data/lib/uffizzi/cli/login.rb
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
require 'uffizzi'
|
|
4
4
|
require 'uffizzi/response_helper'
|
|
5
|
+
require 'uffizzi/helpers/project_helper'
|
|
5
6
|
require 'uffizzi/clients/api/api_client'
|
|
7
|
+
require 'tty-prompt'
|
|
6
8
|
|
|
7
9
|
module Uffizzi
|
|
8
10
|
class Cli::Login
|
|
@@ -15,6 +17,7 @@ module Uffizzi
|
|
|
15
17
|
def run
|
|
16
18
|
Uffizzi.ui.say('Login to Uffizzi to view and manage your previews.')
|
|
17
19
|
server = set_server
|
|
20
|
+
|
|
18
21
|
username = set_username
|
|
19
22
|
password = set_password
|
|
20
23
|
params = prepare_request_params(username, password)
|
|
@@ -30,12 +33,12 @@ module Uffizzi
|
|
|
30
33
|
private
|
|
31
34
|
|
|
32
35
|
def set_server
|
|
33
|
-
config_server = ConfigFile.exists?
|
|
36
|
+
config_server = ConfigFile.exists? ? read_option_from_config(:server) : nil
|
|
34
37
|
@options[:server] || config_server || Uffizzi.ui.ask('Server: ')
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
def set_username
|
|
38
|
-
config_username = ConfigFile.exists?
|
|
41
|
+
config_username = ConfigFile.exists? ? read_option_from_config(:username) : nil
|
|
39
42
|
@options[:username] || config_username || Uffizzi.ui.ask('Username: ')
|
|
40
43
|
end
|
|
41
44
|
|
|
@@ -43,6 +46,10 @@ module Uffizzi
|
|
|
43
46
|
ENV['UFFIZZI_PASSWORD'] || Uffizzi.ui.ask('Password: ', echo: false)
|
|
44
47
|
end
|
|
45
48
|
|
|
49
|
+
def read_option_from_config(option)
|
|
50
|
+
ConfigFile.option_has_value?(option) ? ConfigFile.read_option(option) : nil
|
|
51
|
+
end
|
|
52
|
+
|
|
46
53
|
def prepare_request_params(username, password)
|
|
47
54
|
{
|
|
48
55
|
user: {
|
|
@@ -60,10 +67,77 @@ module Uffizzi
|
|
|
60
67
|
ConfigFile.write_option(:username, username)
|
|
61
68
|
ConfigFile.write_option(:cookie, response[:headers])
|
|
62
69
|
ConfigFile.write_option(:account_id, account[:id])
|
|
70
|
+
|
|
71
|
+
default_project = ConfigFile.read_option(:project)
|
|
72
|
+
return unless default_project
|
|
73
|
+
|
|
74
|
+
check_default_project(default_project, server)
|
|
63
75
|
end
|
|
64
76
|
|
|
65
77
|
def account_valid?(account)
|
|
66
78
|
account[:state] == 'active'
|
|
67
79
|
end
|
|
80
|
+
|
|
81
|
+
def check_default_project(default_project, server)
|
|
82
|
+
check_project_response = fetch_projects(server)
|
|
83
|
+
return ResponseHelper.handle_failed_response(check_project_response) unless ResponseHelper.ok?(check_project_response)
|
|
84
|
+
|
|
85
|
+
projects = check_project_response[:body][:projects]
|
|
86
|
+
slugs = projects.map { |project| project[:slug] }
|
|
87
|
+
return if slugs.include?(default_project)
|
|
88
|
+
|
|
89
|
+
question = "Project '#{default_project}' does not exist. Select one of the following projects or create a new project:"
|
|
90
|
+
choices = projects.map do |project|
|
|
91
|
+
{ name: project[:name], value: project[:slug] }
|
|
92
|
+
end
|
|
93
|
+
all_choices = choices + [{ name: 'Create a new project', value: nil }]
|
|
94
|
+
answer = Uffizzi.prompt.select(question, all_choices)
|
|
95
|
+
return ConfigFile.write_option(:project, answer) if answer
|
|
96
|
+
|
|
97
|
+
create_new_project(server)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def create_new_project(server)
|
|
101
|
+
project_name = Uffizzi.prompt.ask('Project name: ', required: true)
|
|
102
|
+
generated_slug = Uffizzi::ProjectHelper.generate_slug(project_name)
|
|
103
|
+
project_slug = Uffizzi.prompt.ask('Project slug: ', default: generated_slug)
|
|
104
|
+
raise Uffizzi::Error.new('Slug must not content spaces or special characters') unless project_slug.match?(/^[a-zA-Z0-9\-_]+\Z/i)
|
|
105
|
+
|
|
106
|
+
project_description = Uffizzi.prompt.ask('Project desciption: ')
|
|
107
|
+
|
|
108
|
+
params = {
|
|
109
|
+
project: {
|
|
110
|
+
name: project_name.strip,
|
|
111
|
+
slug: project_slug,
|
|
112
|
+
description: project_description,
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
response = create_project(server, params)
|
|
117
|
+
|
|
118
|
+
if ResponseHelper.created?(response)
|
|
119
|
+
handle_create_project_succeess(response)
|
|
120
|
+
else
|
|
121
|
+
handle_create_project_failed(response)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def handle_create_project_failed(response)
|
|
126
|
+
name_error = response[:body][:errors][:name].first
|
|
127
|
+
name_already_exists = name_error && name_error.first == 'Name already exists'
|
|
128
|
+
message = "Project with name #{project_name} already exists. " \
|
|
129
|
+
'Please run $ uffizzi config to set it as a default project'
|
|
130
|
+
raise Uffizzi::Error.new(message) if name_already_exists
|
|
131
|
+
|
|
132
|
+
ResponseHelper.handle_failed_response(response)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def handle_create_project_succeess(response)
|
|
136
|
+
project = response[:body][:project]
|
|
137
|
+
|
|
138
|
+
ConfigFile.write_option(:project, project[:slug])
|
|
139
|
+
|
|
140
|
+
Uffizzi.ui.say("Project #{project[:name]} was successfully created")
|
|
141
|
+
end
|
|
68
142
|
end
|
|
69
143
|
end
|
data/lib/uffizzi/cli/logout.rb
CHANGED
data/lib/uffizzi/cli/preview.rb
CHANGED
|
@@ -119,6 +119,9 @@ module Uffizzi
|
|
|
119
119
|
success = PreviewService.run_containers_deploy(project_slug, deployment)
|
|
120
120
|
|
|
121
121
|
display_deployment_data(deployment, success)
|
|
122
|
+
rescue SystemExit, Interrupt, SocketError
|
|
123
|
+
deployment_id = response[:body][:deployment][:id]
|
|
124
|
+
handle_preview_interruption(deployment_id, ConfigFile.read_option(:server), project_slug)
|
|
122
125
|
end
|
|
123
126
|
|
|
124
127
|
def handle_events_command(deployment_name, project_slug)
|
|
@@ -204,7 +207,7 @@ module Uffizzi
|
|
|
204
207
|
|
|
205
208
|
def prepare_params(file_path)
|
|
206
209
|
begin
|
|
207
|
-
compose_file_data = File.read(file_path)
|
|
210
|
+
compose_file_data = EnvVariablesService.substitute_env_variables(File.read(file_path))
|
|
208
211
|
rescue Errno::ENOENT => e
|
|
209
212
|
raise Uffizzi::Error.new(e.message)
|
|
210
213
|
end
|
data/lib/uffizzi/cli/project.rb
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
require 'uffizzi'
|
|
4
4
|
require 'uffizzi/auth_helper'
|
|
5
5
|
require 'uffizzi/response_helper'
|
|
6
|
+
require 'uffizzi/helpers/project_helper'
|
|
7
|
+
require 'uffizzi/services/project_service'
|
|
6
8
|
|
|
7
9
|
module Uffizzi
|
|
8
10
|
class Cli::Project < Thor
|
|
@@ -27,8 +29,27 @@ module Uffizzi
|
|
|
27
29
|
run('set-default', project_slug: project_slug)
|
|
28
30
|
end
|
|
29
31
|
|
|
32
|
+
desc 'describe [PROJECT_SLUG]', 'describe'
|
|
33
|
+
method_option :output, type: :string, aliases: '-o', enum: ['json', 'pretty'], default: 'json'
|
|
34
|
+
def describe(project_slug)
|
|
35
|
+
run('describe', project_slug: project_slug)
|
|
36
|
+
end
|
|
37
|
+
|
|
30
38
|
map('set-default' => :set_default)
|
|
31
39
|
|
|
40
|
+
method_option :name, required: true
|
|
41
|
+
method_option :slug, default: ''
|
|
42
|
+
method_option :description, required: false
|
|
43
|
+
desc 'create', 'Create a project'
|
|
44
|
+
def create
|
|
45
|
+
run('create')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
desc 'delete [PROJECT_SLUG]', 'Delete a project'
|
|
49
|
+
def delete(project_slug)
|
|
50
|
+
run('delete', project_slug: project_slug)
|
|
51
|
+
end
|
|
52
|
+
|
|
32
53
|
private
|
|
33
54
|
|
|
34
55
|
def run(command, project_slug: nil)
|
|
@@ -39,21 +60,74 @@ module Uffizzi
|
|
|
39
60
|
handle_list_command
|
|
40
61
|
when 'set-default'
|
|
41
62
|
handle_set_default_command(project_slug)
|
|
63
|
+
when 'create'
|
|
64
|
+
handle_create_command
|
|
65
|
+
when 'delete'
|
|
66
|
+
handle_delete_command(project_slug)
|
|
67
|
+
when 'describe'
|
|
68
|
+
handle_describe_command(project_slug)
|
|
42
69
|
end
|
|
43
70
|
end
|
|
44
71
|
|
|
72
|
+
def handle_describe_command(project_slug)
|
|
73
|
+
response = describe_project(ConfigFile.read_option(:server), project_slug)
|
|
74
|
+
|
|
75
|
+
if ResponseHelper.ok?(response)
|
|
76
|
+
handle_succeed_describe_response(response)
|
|
77
|
+
else
|
|
78
|
+
ResponseHelper.handle_failed_response(response)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def handle_succeed_describe_response(response)
|
|
83
|
+
project = response[:body][:project]
|
|
84
|
+
project[:deployments] = ProjectService.select_active_deployments(project)
|
|
85
|
+
ProjectService.describe_project(project, options[:output])
|
|
86
|
+
end
|
|
87
|
+
|
|
45
88
|
def handle_list_command
|
|
46
89
|
server = ConfigFile.read_option(:server)
|
|
47
90
|
response = fetch_projects(server)
|
|
48
91
|
|
|
49
92
|
if ResponseHelper.ok?(response)
|
|
50
|
-
|
|
93
|
+
handle_list_success_response(response)
|
|
51
94
|
else
|
|
52
95
|
ResponseHelper.handle_failed_response(response)
|
|
53
96
|
end
|
|
54
97
|
end
|
|
55
98
|
|
|
56
|
-
def
|
|
99
|
+
def handle_create_command
|
|
100
|
+
name = options[:name]
|
|
101
|
+
slug = options[:slug].empty? ? Uffizzi::ProjectHelper.generate_slug(name) : options[:slug]
|
|
102
|
+
raise Uffizzi::Error.new('Slug must not content spaces or special characters') unless slug.match?(/^[a-zA-Z0-9\-_]+\Z/i)
|
|
103
|
+
|
|
104
|
+
server = ConfigFile.read_option(:server)
|
|
105
|
+
params = {
|
|
106
|
+
name: name,
|
|
107
|
+
description: options[:description],
|
|
108
|
+
slug: slug,
|
|
109
|
+
}
|
|
110
|
+
response = create_project(server, params)
|
|
111
|
+
|
|
112
|
+
if ResponseHelper.created?(response)
|
|
113
|
+
handle_create_success_response(response)
|
|
114
|
+
else
|
|
115
|
+
ResponseHelper.handle_failed_response(response)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def handle_delete_command(project_slug)
|
|
120
|
+
server = ConfigFile.read_option(:server)
|
|
121
|
+
response = delete_project(server, project_slug)
|
|
122
|
+
|
|
123
|
+
if ResponseHelper.no_content?(response)
|
|
124
|
+
Uffizzi.ui.say("Project with slug #{project_slug} was deleted successfully")
|
|
125
|
+
else
|
|
126
|
+
ResponseHelper.handle_failed_response(response)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def handle_list_success_response(response)
|
|
57
131
|
projects = response[:body][:projects]
|
|
58
132
|
return Uffizzi.ui.say('No projects related to this email') if projects.empty?
|
|
59
133
|
|
|
@@ -76,6 +150,12 @@ module Uffizzi
|
|
|
76
150
|
Uffizzi.ui.say('Default project has been updated.')
|
|
77
151
|
end
|
|
78
152
|
|
|
153
|
+
def handle_create_success_response(response)
|
|
154
|
+
project_name = response[:body][:project][:name]
|
|
155
|
+
|
|
156
|
+
Uffizzi.ui.say("Project #{project_name} was successfully created")
|
|
157
|
+
end
|
|
158
|
+
|
|
79
159
|
def print_projects(projects)
|
|
80
160
|
projects_list = projects.reduce('') do |acc, project|
|
|
81
161
|
"#{acc}#{project[:slug]}\n"
|
data/lib/uffizzi/cli.rb
CHANGED
|
@@ -62,8 +62,10 @@ module Uffizzi
|
|
|
62
62
|
return Common.show_manual(filename(args)) if show_help?(args, opts)
|
|
63
63
|
|
|
64
64
|
super
|
|
65
|
-
rescue
|
|
65
|
+
rescue Interrupt
|
|
66
66
|
raise Uffizzi::Error.new('The command was interrupted')
|
|
67
|
+
rescue SocketError
|
|
68
|
+
raise Uffizzi::Error.new('A request was not sent to Uffizzi app')
|
|
67
69
|
end
|
|
68
70
|
|
|
69
71
|
private
|
|
@@ -49,6 +49,20 @@ module ApiClient
|
|
|
49
49
|
build_response(response)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
def create_project(server, params)
|
|
53
|
+
uri = projects_uri(server)
|
|
54
|
+
response = http_client.make_post_request(uri, params)
|
|
55
|
+
|
|
56
|
+
build_response(response)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def delete_project(server, project_slug)
|
|
60
|
+
uri = project_uri(server, project_slug)
|
|
61
|
+
response = http_client.make_delete_request(uri)
|
|
62
|
+
|
|
63
|
+
build_response(response)
|
|
64
|
+
end
|
|
65
|
+
|
|
52
66
|
def create_credential(server, params)
|
|
53
67
|
uri = credentials_uri(server)
|
|
54
68
|
response = http_client.make_post_request(uri, params)
|
|
@@ -221,7 +235,7 @@ module ApiClient
|
|
|
221
235
|
|
|
222
236
|
cookie_content = cookies.first
|
|
223
237
|
cookie = cookie_content.split(';').first
|
|
224
|
-
Uffizzi::ConfigFile.rewrite_cookie(cookie) if Uffizzi::ConfigFile.exists?
|
|
238
|
+
Uffizzi::ConfigFile.rewrite_cookie(cookie) if Uffizzi::ConfigFile.exists? && Uffizzi::ConfigFile.option_has_value?(:cookie)
|
|
225
239
|
http_client.auth_cookie = cookie
|
|
226
240
|
|
|
227
241
|
cookie
|
data/lib/uffizzi/config_file.rb
CHANGED
|
@@ -5,20 +5,15 @@ require 'fileutils'
|
|
|
5
5
|
|
|
6
6
|
module Uffizzi
|
|
7
7
|
class ConfigFile
|
|
8
|
-
CONFIG_PATH = "#{Dir.home}/.config/uffizzi/config_default
|
|
8
|
+
CONFIG_PATH = "#{Dir.home}/.config/uffizzi/config_default"
|
|
9
9
|
|
|
10
10
|
class << self
|
|
11
11
|
def config_path
|
|
12
12
|
CONFIG_PATH
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def create(account_id, cookie, server)
|
|
16
|
-
data = prepare_config_data(account_id, cookie, server)
|
|
17
|
-
data.each_pair { |key, value| write_option(key, value) }
|
|
18
|
-
end
|
|
19
|
-
|
|
20
15
|
def delete
|
|
21
|
-
File.
|
|
16
|
+
File.truncate(config_path, 0) if exists?
|
|
22
17
|
end
|
|
23
18
|
|
|
24
19
|
def exists?
|
|
@@ -73,8 +68,6 @@ module Uffizzi
|
|
|
73
68
|
data
|
|
74
69
|
end
|
|
75
70
|
|
|
76
|
-
private
|
|
77
|
-
|
|
78
71
|
def option_exists?(option)
|
|
79
72
|
data = read
|
|
80
73
|
return false unless data.is_a?(Hash)
|
|
@@ -82,6 +75,8 @@ module Uffizzi
|
|
|
82
75
|
data.key?(option)
|
|
83
76
|
end
|
|
84
77
|
|
|
78
|
+
private
|
|
79
|
+
|
|
85
80
|
def read
|
|
86
81
|
data = File.read(config_path)
|
|
87
82
|
options = data.split("\n")
|
|
@@ -90,7 +85,10 @@ module Uffizzi
|
|
|
90
85
|
acc.merge({ key.strip.to_sym => value.strip })
|
|
91
86
|
end
|
|
92
87
|
rescue Errno::ENOENT => e
|
|
93
|
-
|
|
88
|
+
file_path = e.message.split(' ').last
|
|
89
|
+
message = "Configuration file not found: #{file_path}\n" \
|
|
90
|
+
'To configure the uffizzi CLI interactively, run $ uffizzi config'
|
|
91
|
+
raise Uffizzi::Error.new(message)
|
|
94
92
|
end
|
|
95
93
|
|
|
96
94
|
def write(data)
|
|
@@ -107,14 +105,6 @@ module Uffizzi
|
|
|
107
105
|
end
|
|
108
106
|
end
|
|
109
107
|
|
|
110
|
-
def prepare_config_data(account_id, cookie, server)
|
|
111
|
-
{
|
|
112
|
-
account_id: account_id,
|
|
113
|
-
server: server,
|
|
114
|
-
cookie: cookie,
|
|
115
|
-
}
|
|
116
|
-
end
|
|
117
|
-
|
|
118
108
|
def create_file
|
|
119
109
|
dir = File.dirname(config_path)
|
|
120
110
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Uffizzi
|
|
4
|
+
module ProjectHelper
|
|
5
|
+
SLUG_ENDING_LENGTH = 6
|
|
6
|
+
class << self
|
|
7
|
+
def generate_slug(name)
|
|
8
|
+
formatted_name = name.downcase.gsub(/ /, '-').gsub(/[^\w-]+/, '')
|
|
9
|
+
slug_ending = generate_random_string(SLUG_ENDING_LENGTH)
|
|
10
|
+
|
|
11
|
+
"#{formatted_name}-#{slug_ending}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def generate_random_string(length)
|
|
17
|
+
hexatridecimal_base = 36
|
|
18
|
+
rand(hexatridecimal_base**length).to_s(hexatridecimal_base)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'tty-prompt'
|
|
4
|
+
|
|
5
|
+
module Uffizzi
|
|
6
|
+
module UI
|
|
7
|
+
class Prompt
|
|
8
|
+
def initialize
|
|
9
|
+
@prompt = TTY::Prompt.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def select(question, choices)
|
|
13
|
+
@prompt.select(question, choices)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def ask(message, **args)
|
|
17
|
+
@prompt.ask(message, **args)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|