uffizzi-cli 0.1.4.3 → 0.2.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/Gemfile.lock +5 -1
- data/README.md +67 -26
- data/config/config.rb +17 -0
- data/lib/uffizzi/auth_helper.rb +5 -0
- data/lib/uffizzi/cli/config.rb +28 -20
- data/lib/uffizzi/cli/login.rb +3 -6
- data/lib/uffizzi/cli/preview.rb +267 -0
- data/lib/uffizzi/cli/project/compose.rb +119 -0
- data/lib/uffizzi/cli/project.rb +64 -0
- data/lib/uffizzi/cli.rb +15 -14
- data/lib/uffizzi/clients/api/api_client.rb +71 -5
- data/lib/uffizzi/clients/api/api_routes.rb +24 -0
- data/lib/uffizzi/clients/api/http_client.rb +21 -3
- data/lib/uffizzi/config_file.rb +17 -13
- data/lib/uffizzi/response_helper.rb +24 -0
- data/lib/uffizzi/services/compose_file_service.rb +102 -0
- data/lib/uffizzi/services/env_variables_service.rb +48 -0
- data/lib/uffizzi/version.rb +1 -1
- data/lib/uffizzi.rb +5 -4
- data/man/uffizzi-create +50 -0
- data/man/uffizzi-create.ronn +41 -0
- data/man/uffizzi-delete +37 -0
- data/man/uffizzi-delete.ronn +28 -0
- data/man/uffizzi-describe +38 -0
- data/man/uffizzi-describe.ronn +29 -0
- data/man/uffizzi-list +33 -0
- data/man/uffizzi-list.ronn +25 -0
- data/man/uffizzi-preview +39 -0
- data/man/uffizzi-preview.ronn +33 -0
- data/uffizzi.gemspec +1 -0
- metadata +32 -3
- data/lib/uffizzi/cli/projects.rb +0 -48
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'io/console'
|
4
|
+
require 'uffizzi'
|
5
|
+
require 'uffizzi/auth_helper'
|
6
|
+
require 'uffizzi/response_helper'
|
7
|
+
require 'uffizzi/services/compose_file_service'
|
8
|
+
require 'uffizzi/services/env_variables_service'
|
9
|
+
require 'thor'
|
10
|
+
|
11
|
+
module Uffizzi
|
12
|
+
class CLI::Project::Compose < Thor
|
13
|
+
include ApiClient
|
14
|
+
|
15
|
+
desc 'set', 'set'
|
16
|
+
def set
|
17
|
+
run(options, 'set')
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'unset', 'unset'
|
21
|
+
def unset
|
22
|
+
run(options, 'unset')
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'describe', 'describe'
|
26
|
+
def describe
|
27
|
+
run(options, 'describe')
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def run(options, command)
|
33
|
+
return Uffizzi.ui.say('You are not logged in.') unless Uffizzi::AuthHelper.signed_in?
|
34
|
+
return Uffizzi.ui.say('This command needs project to be set in config file') unless Uffizzi::AuthHelper.project_set?
|
35
|
+
|
36
|
+
file_path = options[:file]
|
37
|
+
case command
|
38
|
+
when 'set'
|
39
|
+
handle_set_command(file_path)
|
40
|
+
when 'unset'
|
41
|
+
handle_unset_command
|
42
|
+
when 'describe'
|
43
|
+
handle_describe_command
|
44
|
+
when 'validate'
|
45
|
+
handle_validate_command(file_path)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def handle_set_command(file_path)
|
50
|
+
return Uffizzi.ui.say('No file provided') if file_path.nil?
|
51
|
+
|
52
|
+
hostname = ConfigFile.read_option(:hostname)
|
53
|
+
project_slug = ConfigFile.read_option(:project)
|
54
|
+
params = prepare_params(file_path)
|
55
|
+
response = set_compose_file(hostname, params, project_slug)
|
56
|
+
|
57
|
+
if ResponseHelper.created?(response)
|
58
|
+
Uffizzi.ui.say('compose file created')
|
59
|
+
else
|
60
|
+
ResponseHelper.handle_failed_response(response)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def handle_unset_command
|
65
|
+
hostname = ConfigFile.read_option(:hostname)
|
66
|
+
project_slug = ConfigFile.read_option(:project)
|
67
|
+
response = unset_compose_file(hostname, project_slug)
|
68
|
+
|
69
|
+
if ResponseHelper.no_content?(response)
|
70
|
+
Uffizzi.ui.say('compose file deleted')
|
71
|
+
else
|
72
|
+
ResponseHelper.handle_failed_response(response)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def handle_describe_command
|
77
|
+
hostname = ConfigFile.read_option(:hostname)
|
78
|
+
project_slug = ConfigFile.read_option(:project)
|
79
|
+
response = describe_compose_file(hostname, project_slug)
|
80
|
+
compose_file = response[:body][:compose_file]
|
81
|
+
|
82
|
+
if ResponseHelper.ok?(response)
|
83
|
+
if compose_file_valid?(compose_file)
|
84
|
+
Uffizzi.ui.say(Base64.decode64(compose_file[:content]))
|
85
|
+
else
|
86
|
+
ResponseHelper.handle_invalid_compose_response(response)
|
87
|
+
end
|
88
|
+
else
|
89
|
+
ResponseHelper.handle_failed_response(response)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def compose_file_valid?(compose_file)
|
94
|
+
compose_file[:state] == 'valid_file'
|
95
|
+
end
|
96
|
+
|
97
|
+
def prepare_params(file_path)
|
98
|
+
begin
|
99
|
+
compose_file_data = EnvVariablesService.substitute_env_variables(File.read(file_path))
|
100
|
+
rescue Errno::ENOENT => e
|
101
|
+
return Uffizzi.ui.say(e)
|
102
|
+
end
|
103
|
+
|
104
|
+
compose_file_dir = File.dirname(file_path)
|
105
|
+
dependencies = ComposeFileService.parse(compose_file_data, compose_file_dir)
|
106
|
+
absolute_path = File.absolute_path(file_path)
|
107
|
+
compose_file_params = {
|
108
|
+
path: absolute_path,
|
109
|
+
content: Base64.encode64(compose_file_data),
|
110
|
+
source: absolute_path,
|
111
|
+
}
|
112
|
+
|
113
|
+
{
|
114
|
+
compose_file: compose_file_params,
|
115
|
+
dependencies: dependencies,
|
116
|
+
}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'io/console'
|
4
|
+
require 'uffizzi'
|
5
|
+
require 'uffizzi/auth_helper'
|
6
|
+
require 'uffizzi/response_helper'
|
7
|
+
require 'thor'
|
8
|
+
|
9
|
+
module Uffizzi
|
10
|
+
class CLI::Project < Thor
|
11
|
+
include ApiClient
|
12
|
+
|
13
|
+
desc 'compose', 'compose'
|
14
|
+
method_option :file, required: false, aliases: '-f'
|
15
|
+
require_relative 'project/compose'
|
16
|
+
subcommand 'compose', Uffizzi::CLI::Project::Compose
|
17
|
+
|
18
|
+
desc 'list', 'list'
|
19
|
+
def list
|
20
|
+
run('list')
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def run(command)
|
26
|
+
return Uffizzi.ui.say('You are not logged in.') unless Uffizzi::AuthHelper.signed_in?
|
27
|
+
|
28
|
+
case command
|
29
|
+
when 'list'
|
30
|
+
handle_list_command
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def handle_list_command
|
35
|
+
hostname = ConfigFile.read_option(:hostname)
|
36
|
+
response = fetch_projects(hostname)
|
37
|
+
|
38
|
+
if ResponseHelper.ok?(response)
|
39
|
+
handle_succeed_response(response)
|
40
|
+
else
|
41
|
+
ResponseHelper.handle_failed_response(response)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def handle_succeed_response(response)
|
46
|
+
projects = response[:body][:projects]
|
47
|
+
return Uffizzi.ui.say('No projects related to this email') if projects.empty?
|
48
|
+
|
49
|
+
set_default_project(projects.first) if projects.size == 1
|
50
|
+
print_projects(projects)
|
51
|
+
end
|
52
|
+
|
53
|
+
def print_projects(projects)
|
54
|
+
projects_list = projects.reduce('') do |acc, project|
|
55
|
+
"#{acc}#{project[:slug]}\n"
|
56
|
+
end
|
57
|
+
Uffizzi.ui.say(projects_list)
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_default_project(project)
|
61
|
+
ConfigFile.write_option(:project, project[:slug])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/uffizzi/cli.rb
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'thor'
|
4
|
+
require 'uffizzi'
|
4
5
|
|
5
6
|
module Uffizzi
|
6
7
|
class CLI < Thor
|
7
8
|
require_relative 'cli/common'
|
9
|
+
class_option :help, type: :boolean, aliases: ['-h', 'help']
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
desc 'version', 'Show Version'
|
11
|
+
desc 'version', 'show version'
|
12
12
|
def version
|
13
13
|
require_relative 'version'
|
14
|
-
|
14
|
+
Uffizzi.ui.say(Uffizzi::VERSION)
|
15
15
|
end
|
16
16
|
|
17
17
|
desc 'login', 'Login into Uffizzi'
|
18
18
|
method_option :user, required: true, aliases: '-u'
|
19
|
-
method_option :hostname, required: true
|
19
|
+
method_option :hostname, required: true
|
20
20
|
def login
|
21
21
|
require_relative 'cli/login'
|
22
22
|
Login.new(options).run
|
@@ -30,16 +30,17 @@ module Uffizzi
|
|
30
30
|
Logout.new.run
|
31
31
|
end
|
32
32
|
|
33
|
-
desc '
|
34
|
-
|
35
|
-
|
36
|
-
Projects.new.run
|
37
|
-
end
|
33
|
+
desc 'project', 'project'
|
34
|
+
require_relative 'cli/project'
|
35
|
+
subcommand 'project', CLI::Project
|
38
36
|
|
39
37
|
desc 'config', 'config'
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
require_relative 'cli/config'
|
39
|
+
subcommand 'config', CLI::Config
|
40
|
+
|
41
|
+
desc 'preview', 'preview'
|
42
|
+
method_option :project, required: false
|
43
|
+
require_relative 'cli/preview'
|
44
|
+
subcommand 'preview', CLI::Preview
|
44
45
|
end
|
45
46
|
end
|
@@ -7,27 +7,93 @@ module ApiClient
|
|
7
7
|
include ApiRoutes
|
8
8
|
def create_session(hostname, params = {})
|
9
9
|
uri = session_uri(hostname)
|
10
|
-
response = Uffizzi::HttpClient.
|
10
|
+
response = Uffizzi::HttpClient.make_post_request(uri, params, false)
|
11
11
|
|
12
12
|
build_response(response)
|
13
13
|
end
|
14
14
|
|
15
15
|
def destroy_session(hostname)
|
16
16
|
uri = session_uri(hostname)
|
17
|
-
response = Uffizzi::HttpClient.
|
17
|
+
response = Uffizzi::HttpClient.make_delete_request(uri)
|
18
18
|
|
19
19
|
build_response(response)
|
20
20
|
end
|
21
21
|
|
22
22
|
def fetch_projects(hostname)
|
23
23
|
uri = projects_uri(hostname)
|
24
|
-
response = Uffizzi::HttpClient.
|
24
|
+
response = Uffizzi::HttpClient.make_get_request(uri)
|
25
25
|
|
26
26
|
build_response(response)
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
30
|
-
|
29
|
+
def set_compose_file(hostname, params, project_slug)
|
30
|
+
uri = compose_file_uri(hostname, project_slug)
|
31
|
+
response = Uffizzi::HttpClient.make_post_request(uri, params)
|
32
|
+
|
33
|
+
build_response(response)
|
34
|
+
end
|
35
|
+
|
36
|
+
def unset_compose_file(hostname, project_slug)
|
37
|
+
uri = compose_file_uri(hostname, project_slug)
|
38
|
+
response = Uffizzi::HttpClient.make_delete_request(uri, true)
|
39
|
+
|
40
|
+
build_response(response)
|
41
|
+
end
|
42
|
+
|
43
|
+
def describe_compose_file(hostname, project_slug)
|
44
|
+
uri = compose_file_uri(hostname, project_slug)
|
45
|
+
response = Uffizzi::HttpClient.make_get_request(uri)
|
46
|
+
|
47
|
+
build_response(response)
|
48
|
+
end
|
49
|
+
|
50
|
+
def validate_compose_file(hostname, project_slug)
|
51
|
+
uri = validate_compose_file_uri(hostname, project_slug)
|
52
|
+
response = Uffizzi::HttpClient.make_get_request(uri)
|
53
|
+
|
54
|
+
build_response(response)
|
55
|
+
end
|
56
|
+
|
57
|
+
def fetch_deployments(hostname, project_slug)
|
58
|
+
uri = deployments_uri(hostname, project_slug)
|
59
|
+
response = Uffizzi::HttpClient.make_get_request(uri)
|
60
|
+
|
61
|
+
build_response(response)
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_deployment(hostname, project_slug, params)
|
65
|
+
uri = deployments_uri(hostname, project_slug)
|
66
|
+
response = Uffizzi::HttpClient.make_post_request(uri, params)
|
67
|
+
|
68
|
+
build_response(response)
|
69
|
+
end
|
70
|
+
|
71
|
+
def delete_deployment(hostname, project_slug, deployment_id)
|
72
|
+
uri = deployment_uri(hostname, project_slug, deployment_id)
|
73
|
+
response = Uffizzi::HttpClient.make_delete_request(uri, true)
|
74
|
+
|
75
|
+
build_response(response)
|
76
|
+
end
|
77
|
+
|
78
|
+
def describe_deployment(hostname, project_slug, deployment_id)
|
79
|
+
uri = deployment_uri(hostname, project_slug, deployment_id)
|
80
|
+
response = Uffizzi::HttpClient.make_get_request(uri)
|
81
|
+
|
82
|
+
build_response(response)
|
83
|
+
end
|
84
|
+
|
85
|
+
def get_activity_items(hostname, project_slug, deployment_id)
|
86
|
+
uri = activity_items_uri(hostname, project_slug, deployment_id)
|
87
|
+
response = Uffizzi::HttpClient.make_get_request(uri)
|
88
|
+
|
89
|
+
build_response(response)
|
90
|
+
end
|
91
|
+
|
92
|
+
def deploy_containers(hostname, project_slug, deployment_id, params)
|
93
|
+
uri = deploy_containers_uri(hostname, project_slug, deployment_id)
|
94
|
+
response = Uffizzi::HttpClient.make_post_request(uri, params)
|
95
|
+
|
96
|
+
build_response(response)
|
31
97
|
end
|
32
98
|
|
33
99
|
private
|
@@ -8,4 +8,28 @@ module ApiRoutes
|
|
8
8
|
def projects_uri(hostname)
|
9
9
|
"#{hostname}/api/cli/v1/projects"
|
10
10
|
end
|
11
|
+
|
12
|
+
def compose_file_uri(hostname, project_slug)
|
13
|
+
"#{hostname}/api/cli/v1/projects/#{project_slug}/compose_file"
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_compose_file_uri(hostname, project_slug)
|
17
|
+
"#{compose_files_uri(hostname, project_slug)}/validate"
|
18
|
+
end
|
19
|
+
|
20
|
+
def deployments_uri(hostname, project_slug)
|
21
|
+
"#{hostname}/api/cli/v1/projects/#{project_slug}/deployments"
|
22
|
+
end
|
23
|
+
|
24
|
+
def deployment_uri(hostname, project_slug, deployment_id)
|
25
|
+
"#{hostname}/api/cli/v1/projects/#{project_slug}/deployments/#{deployment_id}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def activity_items_uri(hostname, project_slug, deployment_id)
|
29
|
+
"#{hostname}/api/cli/v1/projects/#{project_slug}/deployments/#{deployment_id}/activity_items"
|
30
|
+
end
|
31
|
+
|
32
|
+
def deploy_containers_uri(hostname, project_slug, deployment_id)
|
33
|
+
"#{hostname}/api/cli/v1/projects/#{project_slug}/deployments/#{deployment_id}/deploy_containers"
|
34
|
+
end
|
11
35
|
end
|
@@ -3,11 +3,30 @@
|
|
3
3
|
require 'net/http'
|
4
4
|
require 'json'
|
5
5
|
require 'uffizzi/config_file'
|
6
|
+
require 'uffizzi/response_helper'
|
6
7
|
|
7
8
|
module Uffizzi
|
8
9
|
class HttpClient
|
9
10
|
class << self
|
10
|
-
def
|
11
|
+
def make_get_request(request_uri, cookies_required = true)
|
12
|
+
make_request(:get, request_uri, cookies_required)
|
13
|
+
end
|
14
|
+
|
15
|
+
def make_post_request(request_uri, params = {}, cookies_required = true)
|
16
|
+
make_request(:post, request_uri, cookies_required, params)
|
17
|
+
end
|
18
|
+
|
19
|
+
def make_put_request(request_uri, cookies_required = true)
|
20
|
+
make_request(:put, request_uri, cookies_required)
|
21
|
+
end
|
22
|
+
|
23
|
+
def make_delete_request(request_uri, cookies_required = true)
|
24
|
+
make_request(:delete, request_uri, cookies_required)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def make_request(method, request_uri, require_cookies, params = {})
|
11
30
|
uri = URI(request_uri)
|
12
31
|
use_ssl = request_uri.start_with?('https')
|
13
32
|
|
@@ -24,8 +43,6 @@ module Uffizzi
|
|
24
43
|
response
|
25
44
|
end
|
26
45
|
|
27
|
-
private
|
28
|
-
|
29
46
|
def build_request(uri, params, method, require_cookies)
|
30
47
|
headers = { 'Content-Type' => 'application/json' }
|
31
48
|
request = case method
|
@@ -45,6 +62,7 @@ module Uffizzi
|
|
45
62
|
if ConfigFile.exists? && ConfigFile.option_exists?(:basic_auth_user) && ConfigFile.option_exists?(:basic_auth_password)
|
46
63
|
request.basic_auth(ConfigFile.read_option(:basic_auth_user), ConfigFile.read_option(:basic_auth_password))
|
47
64
|
end
|
65
|
+
|
48
66
|
request
|
49
67
|
end
|
50
68
|
end
|
data/lib/uffizzi/config_file.rb
CHANGED
@@ -23,22 +23,21 @@ module Uffizzi
|
|
23
23
|
|
24
24
|
def read_option(option)
|
25
25
|
data = read
|
26
|
-
return nil
|
26
|
+
return nil unless data.is_a?(Hash)
|
27
27
|
|
28
|
-
puts "The option #{option} doesn't exist in config file" if data[option].nil?
|
29
28
|
data[option]
|
30
29
|
end
|
31
30
|
|
32
31
|
def option_exists?(option)
|
33
32
|
data = read
|
34
|
-
return false
|
33
|
+
return false unless data.is_a?(Hash)
|
35
34
|
|
36
35
|
data.key?(option)
|
37
36
|
end
|
38
37
|
|
39
38
|
def write_option(key, value)
|
40
39
|
data = exists? ? read : {}
|
41
|
-
return nil
|
40
|
+
return nil unless data.is_a?(Hash)
|
42
41
|
|
43
42
|
data[key] = value
|
44
43
|
write(data.to_json)
|
@@ -46,7 +45,7 @@ module Uffizzi
|
|
46
45
|
|
47
46
|
def delete_option(key)
|
48
47
|
data = read
|
49
|
-
return nil
|
48
|
+
return nil unless data.is_a?(Hash)
|
50
49
|
|
51
50
|
new_data = data.except(key)
|
52
51
|
write(new_data.to_json)
|
@@ -58,11 +57,16 @@ module Uffizzi
|
|
58
57
|
|
59
58
|
def list
|
60
59
|
data = read
|
61
|
-
return nil
|
60
|
+
return nil unless data.is_a?(Hash)
|
62
61
|
|
63
|
-
data.
|
64
|
-
|
62
|
+
content = data.reduce('') do |acc, pair|
|
63
|
+
property, value = pair
|
64
|
+
"#{acc}#{property} - #{value}\n"
|
65
65
|
end
|
66
|
+
|
67
|
+
Uffizzi.ui.say(content)
|
68
|
+
|
69
|
+
data
|
66
70
|
end
|
67
71
|
|
68
72
|
private
|
@@ -70,9 +74,11 @@ module Uffizzi
|
|
70
74
|
def read
|
71
75
|
JSON.parse(File.read(CONFIG_PATH), symbolize_names: true)
|
72
76
|
rescue Errno::ENOENT => e
|
73
|
-
|
77
|
+
Uffizzi.ui.say(e)
|
78
|
+
nil
|
74
79
|
rescue JSON::ParserError
|
75
|
-
|
80
|
+
Uffizzi.ui.say('Config file is in incorrect format')
|
81
|
+
nil
|
76
82
|
end
|
77
83
|
|
78
84
|
def write(data)
|
@@ -92,9 +98,7 @@ module Uffizzi
|
|
92
98
|
def create_file
|
93
99
|
dir = File.dirname(CONFIG_PATH)
|
94
100
|
|
95
|
-
unless File.directory?(dir)
|
96
|
-
FileUtils.mkdir_p(dir)
|
97
|
-
end
|
101
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
98
102
|
|
99
103
|
File.new(CONFIG_PATH, 'w')
|
100
104
|
end
|
@@ -22,6 +22,30 @@ module Uffizzi
|
|
22
22
|
def no_content?(response)
|
23
23
|
response[:code] == Net::HTTPNoContent
|
24
24
|
end
|
25
|
+
|
26
|
+
def ok?(response)
|
27
|
+
response[:code] == Net::HTTPOK
|
28
|
+
end
|
29
|
+
|
30
|
+
def handle_failed_response(response)
|
31
|
+
print_errors(response[:body][:errors])
|
32
|
+
end
|
33
|
+
|
34
|
+
def handle_invalid_compose_response(response)
|
35
|
+
print_errors(response[:body][:compose_file][:payload][:errors])
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def print_errors(errors)
|
41
|
+
errors.each_key do |key|
|
42
|
+
if errors[key].is_a?(Array)
|
43
|
+
errors[key].each { |error_message| Uffizzi.ui.say(error_message) }
|
44
|
+
else
|
45
|
+
Uffizzi.ui.say(errors[key])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
25
49
|
end
|
26
50
|
end
|
27
51
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'psych'
|
4
|
+
require 'pathname'
|
5
|
+
require 'base64'
|
6
|
+
|
7
|
+
class ComposeFileService
|
8
|
+
class << self
|
9
|
+
def parse(compose_content, compose_file_path)
|
10
|
+
compose_data = parse_compose_content_to_object(compose_content)
|
11
|
+
|
12
|
+
env_files = prepare_services_env_files(compose_data['services']).flatten.uniq
|
13
|
+
config_files = fetch_configs(compose_data['configs'])
|
14
|
+
prepare_dependencies(env_files, config_files, compose_file_path)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def prepare_dependencies(env_files, config_files, compose_file_path)
|
20
|
+
prepare_dependency_files_data(env_files + config_files, compose_file_path)
|
21
|
+
end
|
22
|
+
|
23
|
+
def prepare_dependency_files_data(dependency_files, compose_file_path)
|
24
|
+
dependency_files.map do |dependency_file|
|
25
|
+
dependency_file_data = Psych.load(File.read("#{compose_file_path}/#{dependency_file}"))
|
26
|
+
{
|
27
|
+
path: dependency_file,
|
28
|
+
source: dependency_file,
|
29
|
+
content: Base64.encode64(dependency_file_data),
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def fetch_configs(configs_data)
|
35
|
+
return [] if configs_data.nil?
|
36
|
+
|
37
|
+
Uffizzi.ui.say("Unsupported type of #{:configs} option") unless configs_data.is_a?(Hash)
|
38
|
+
|
39
|
+
configs = []
|
40
|
+
configs_data.each_pair do |config_name, config_data|
|
41
|
+
Uffizzi.ui.say("#{config_name} has an empty file") if config_data['file'].empty? || config_data['file'].nil?
|
42
|
+
|
43
|
+
configs << prepare_file_path(config_data['file'])
|
44
|
+
end
|
45
|
+
|
46
|
+
configs
|
47
|
+
end
|
48
|
+
|
49
|
+
def prepare_file_path(file_path)
|
50
|
+
pathname = Pathname.new(file_path)
|
51
|
+
|
52
|
+
pathname.cleanpath.to_s.strip.delete_prefix('/')
|
53
|
+
end
|
54
|
+
|
55
|
+
def parse_env_file(env_file)
|
56
|
+
case env_file
|
57
|
+
when String
|
58
|
+
Uffizzi.ui.say('env_file contains an empty value') if env_file.nil? || env_file.empty?
|
59
|
+
[prepare_file_path(env_file)]
|
60
|
+
when Array
|
61
|
+
Uffizzi.ui.say('env_file contains an empty value') if env_file.any? { |file| file.nil? || file.empty? }
|
62
|
+
env_file.map { |env_file_path| prepare_file_path(env_file_path) }
|
63
|
+
else
|
64
|
+
Uffizzi.ui.say("Unsupported type of #{:env_file} option")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def prepare_services_env_files(services)
|
69
|
+
return [] if services.nil?
|
70
|
+
|
71
|
+
services.keys.map do |service|
|
72
|
+
service_env_files = prepare_service_env_files(services.fetch(service))
|
73
|
+
|
74
|
+
service_env_files
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def prepare_service_env_files(service_data)
|
79
|
+
env_files_data = []
|
80
|
+
service_data.each_pair do |key, value|
|
81
|
+
key_sym = key.to_sym
|
82
|
+
if key_sym == :env_file
|
83
|
+
env_files_data << parse_env_file(value)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
env_files_data
|
88
|
+
end
|
89
|
+
|
90
|
+
def parse_compose_content_to_object(compose_content)
|
91
|
+
begin
|
92
|
+
compose_data = Psych.safe_load(compose_content)
|
93
|
+
rescue Psych::SyntaxError
|
94
|
+
Uffizzi.ui.say('Invalid compose file')
|
95
|
+
end
|
96
|
+
|
97
|
+
Uffizzi.ui.say('Unsupported compose file') if compose_data.nil?
|
98
|
+
|
99
|
+
compose_data
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'psych'
|
4
|
+
require 'pathname'
|
5
|
+
require 'base64'
|
6
|
+
|
7
|
+
class EnvVariablesService
|
8
|
+
class << self
|
9
|
+
def substitute_env_variables(compose_file_data)
|
10
|
+
compose_file_data.gsub(/\$\{?([?:\-_A-Za-z0-9]+)\}?/) do |variable|
|
11
|
+
variable_content = variable.match(/[?:\-_A-Za-z0-9]+/).to_s
|
12
|
+
fetch_variable_value(variable_content)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def fetch_variable_value(variable_content)
|
19
|
+
variable_name = variable_content.match(/^[_A-Za-z0-9]+/).to_s
|
20
|
+
variable_value = ENV[variable_name]
|
21
|
+
return variable_value unless variable_value.nil?
|
22
|
+
return fetch_variable_default_value(variable_content) if variable_has_default_value?(variable_content)
|
23
|
+
|
24
|
+
error_message = if variable_has_error_message?(variable_content)
|
25
|
+
fetch_env_error_message(variable_content)
|
26
|
+
else
|
27
|
+
"Environment variable #{variable_name} doesn't exist"
|
28
|
+
end
|
29
|
+
raise StandardError.new(error_message)
|
30
|
+
end
|
31
|
+
|
32
|
+
def variable_has_default_value?(variable_content)
|
33
|
+
variable_content.include?('-')
|
34
|
+
end
|
35
|
+
|
36
|
+
def fetch_variable_default_value(variable_content)
|
37
|
+
variable_content.split('-', 2).last
|
38
|
+
end
|
39
|
+
|
40
|
+
def variable_has_error_message?(variable_content)
|
41
|
+
variable_content.include?('?')
|
42
|
+
end
|
43
|
+
|
44
|
+
def fetch_env_error_message(variable_content)
|
45
|
+
variable_content.split('?', 2).last
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/uffizzi/version.rb
CHANGED