envirobly 0.10.0 → 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.
- checksums.yaml +4 -4
- data/lib/envirobly/access_token.rb +67 -16
- data/lib/envirobly/api.rb +42 -23
- data/lib/envirobly/cli/main.rb +65 -70
- data/lib/envirobly/colorize.rb +33 -0
- data/lib/envirobly/config.rb +38 -0
- data/lib/envirobly/default.rb +47 -0
- data/lib/envirobly/defaults/account.rb +46 -0
- data/lib/envirobly/defaults/project.rb +4 -0
- data/lib/envirobly/defaults/region.rb +45 -0
- data/lib/envirobly/defaults.rb +2 -0
- data/lib/envirobly/deployment.rb +28 -17
- data/lib/envirobly/duration.rb +1 -1
- data/lib/envirobly/git/commit.rb +2 -2
- data/lib/envirobly/version.rb +1 -1
- data/lib/envirobly.rb +2 -2
- metadata +34 -44
- data/lib/core_ext.rb +0 -113
- data/lib/envirobly/configs.rb +0 -79
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ef94e7e6db204bc73126d41dae8d3417e4ea7ac35e7cbecd5d496dcee842ee3
|
4
|
+
data.tar.gz: 32f53215e81d8e3d984cd7caf58fc0944c9636ba587e59dbd4573bfcd04f8a08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef5d512c3dab84e7f4cc5ce45804d30cce526b61c83407895952536a45a901715aee2ceb39b71e5b8d68d8e477f20b4628f9f94df41a932f603a511e3d9fface
|
7
|
+
data.tar.gz: d5444e2eb995be568dcc57e7df33145d2b17792f212c9ed605a3c456d511f0e2b80968d4900642c3483d9eb01afb550e1b0071f212877706a8e7a9e265d87a9e
|
@@ -2,35 +2,86 @@ require "fileutils"
|
|
2
2
|
require "pathname"
|
3
3
|
|
4
4
|
class Envirobly::AccessToken
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
include Envirobly::Colorize
|
6
|
+
|
7
|
+
attr_reader :shell
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def destroy
|
11
|
+
if File.exist?(path)
|
12
|
+
FileUtils.rm path
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def dir
|
17
|
+
if ENV["XDG_CONFIG_HOME"]
|
18
|
+
Pathname.new(ENV["XDG_CONFIG_HOME"]).join("envirobly")
|
19
|
+
else
|
20
|
+
Pathname.new(Dir.home).join(".envirobly")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def path
|
25
|
+
dir.join "access_token"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(token = ENV["ENVIROBLY_ACCESS_TOKEN"].presence, shell: nil)
|
30
|
+
@shell = shell
|
31
|
+
|
32
|
+
if token.blank? && File.exist?(self.class.path)
|
33
|
+
@token = File.read(self.class.path)
|
8
34
|
else
|
9
35
|
@token = token
|
10
36
|
end
|
11
37
|
end
|
12
38
|
|
13
39
|
def save
|
14
|
-
FileUtils.mkdir_p
|
15
|
-
File.write
|
16
|
-
File.chmod 0600,
|
17
|
-
puts "Access token saved to #{access_token_path}"
|
40
|
+
FileUtils.mkdir_p self.class.dir
|
41
|
+
File.write self.class.path, @token
|
42
|
+
File.chmod 0600, self.class.path
|
18
43
|
end
|
19
44
|
|
20
45
|
def as_http_bearer
|
21
46
|
"Bearer #{@token}"
|
22
47
|
end
|
23
48
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
49
|
+
def require!
|
50
|
+
return if @token.present?
|
51
|
+
|
52
|
+
shell.say "This action requires you to be signed in."
|
53
|
+
shell.say "Please visit https://on.envirobly.com/profile/access_tokens"
|
54
|
+
shell.say "to generate an access token and then paste it in here."
|
55
|
+
shell.say
|
56
|
+
|
57
|
+
set
|
58
|
+
end
|
59
|
+
|
60
|
+
def set
|
61
|
+
@token = nil
|
62
|
+
|
63
|
+
while @token.blank?
|
64
|
+
begin
|
65
|
+
@token = shell.ask("Access Token:", echo: false)
|
66
|
+
rescue Interrupt
|
67
|
+
shell.say
|
68
|
+
shell.say_error "Cancelled"
|
69
|
+
exit
|
30
70
|
end
|
31
|
-
end
|
32
71
|
|
33
|
-
|
34
|
-
|
72
|
+
api = Envirobly::Api.new(access_token: self)
|
73
|
+
|
74
|
+
# TODO: Eventually replace with custom `whoami` API that returns name, email...
|
75
|
+
if api.list_accounts.success?
|
76
|
+
save
|
77
|
+
shell.say
|
78
|
+
shell.say "Successfully signed in "
|
79
|
+
shell.say green_check
|
80
|
+
else
|
81
|
+
shell.say
|
82
|
+
shell.say_error "This token is invalid. Please try again"
|
83
|
+
@token = nil
|
84
|
+
end
|
35
85
|
end
|
86
|
+
end
|
36
87
|
end
|
data/lib/envirobly/api.rb
CHANGED
@@ -4,17 +4,17 @@ require "socket"
|
|
4
4
|
require "uri"
|
5
5
|
|
6
6
|
class Envirobly::Api
|
7
|
-
HOST = ENV["ENVIROBLY_API_HOST"] || "envirobly.com"
|
7
|
+
HOST = ENV["ENVIROBLY_API_HOST"].presence || "on.envirobly.com"
|
8
8
|
USER_AGENT = "Envirobly CLI v#{Envirobly::VERSION}"
|
9
9
|
CONTENT_TYPE = "application/json"
|
10
10
|
|
11
|
-
def initialize
|
12
|
-
@access_token =
|
11
|
+
def initialize(access_token: Envirobly::AccessToken.new)
|
12
|
+
@access_token = access_token
|
13
13
|
end
|
14
14
|
|
15
15
|
def validate_shape(params)
|
16
16
|
post_as_json(api_v1_shape_validations_url, params:, headers: authorization_headers).tap do |response|
|
17
|
-
unless
|
17
|
+
unless response.success?
|
18
18
|
$stderr.puts "Validation request responded with #{response.code}. Aborting."
|
19
19
|
exit 1
|
20
20
|
end
|
@@ -22,29 +22,36 @@ class Envirobly::Api
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def create_deployment(params)
|
25
|
-
post_as_json(api_v1_deployments_url, params:, headers: authorization_headers)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
exit 1
|
31
|
-
end
|
32
|
-
end
|
25
|
+
post_as_json(api_v1_deployments_url, params:, headers: authorization_headers)
|
26
|
+
end
|
27
|
+
|
28
|
+
def list_accounts
|
29
|
+
get_as_json api_v1_accounts_url, headers: authorization_headers
|
33
30
|
end
|
34
31
|
|
35
|
-
|
36
|
-
|
32
|
+
def list_regions
|
33
|
+
get_as_json api_v1_regions_url, headers: authorization_headers
|
34
|
+
end
|
35
|
+
|
36
|
+
MAX_RETRIES = 30
|
37
|
+
SHORT_RETRY_INTERVAL = 2.seconds
|
38
|
+
LONG_RETRY_INTERVAL = 6.seconds
|
37
39
|
def get_deployment_with_delay_and_retry(url, tries = 1)
|
38
|
-
sleep
|
40
|
+
sleep SHORT_RETRY_INTERVAL * tries
|
39
41
|
response = get_as_json URI(url)
|
40
42
|
|
41
|
-
if
|
43
|
+
if response.success?
|
42
44
|
response
|
43
45
|
elsif MAX_RETRIES <= tries
|
44
46
|
$stderr.puts "Max retries exhausted while waiting for deployment credentials. Aborting."
|
45
47
|
exit 1
|
46
48
|
else
|
47
|
-
|
49
|
+
if tries > 3
|
50
|
+
sleep LONG_RETRY_INTERVAL
|
51
|
+
else
|
52
|
+
sleep SHORT_RETRY_INTERVAL
|
53
|
+
end
|
54
|
+
|
48
55
|
get_deployment_with_delay_and_retry(url, tries + 1)
|
49
56
|
end
|
50
57
|
end
|
@@ -67,11 +74,23 @@ class Envirobly::Api
|
|
67
74
|
|
68
75
|
private
|
69
76
|
def api_v1_shape_validations_url
|
70
|
-
|
77
|
+
api_url_for "v1/shape_validations"
|
71
78
|
end
|
72
79
|
|
73
80
|
def api_v1_deployments_url
|
74
|
-
|
81
|
+
api_url_for "v1/deployments"
|
82
|
+
end
|
83
|
+
|
84
|
+
def api_v1_accounts_url
|
85
|
+
api_url_for "v1/accounts"
|
86
|
+
end
|
87
|
+
|
88
|
+
def api_v1_regions_url
|
89
|
+
api_url_for "v1/regions"
|
90
|
+
end
|
91
|
+
|
92
|
+
def api_url_for(path)
|
93
|
+
URI::HTTPS.build(host: HOST, path: "/api/#{path}")
|
75
94
|
end
|
76
95
|
|
77
96
|
def request(url, type:, headers: {})
|
@@ -91,6 +110,10 @@ class Envirobly::Api
|
|
91
110
|
def response.object
|
92
111
|
@json_parsed_body ||= JSON.parse(body)
|
93
112
|
end
|
113
|
+
|
114
|
+
def response.success?
|
115
|
+
(200..299).include?(code.to_i)
|
116
|
+
end
|
94
117
|
end
|
95
118
|
end
|
96
119
|
|
@@ -101,8 +124,4 @@ class Envirobly::Api
|
|
101
124
|
def authorization_headers
|
102
125
|
{ "Authorization" => @access_token.as_http_bearer }
|
103
126
|
end
|
104
|
-
|
105
|
-
def successful_response?(response)
|
106
|
-
(200..299).include?(response.code.to_i)
|
107
|
-
end
|
108
127
|
end
|
data/lib/envirobly/cli/main.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
class Envirobly::Cli::Main < Envirobly::Base
|
2
|
+
include Envirobly::Colorize
|
3
|
+
|
2
4
|
desc "version", "Show Envirobly CLI version"
|
3
5
|
method_option :pure, type: :boolean, default: false
|
4
6
|
def version
|
@@ -9,104 +11,97 @@ class Envirobly::Cli::Main < Envirobly::Base
|
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
14
|
+
desc "signin", "Set access token generated at Envirobly"
|
15
|
+
def signin
|
16
|
+
access_token = Envirobly::AccessToken.new(shell:)
|
17
|
+
access_token.set
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "signout", "Sign out"
|
21
|
+
def signout
|
22
|
+
Envirobly::AccessToken.destroy
|
23
|
+
say "You've signed out."
|
24
|
+
say "This didn't delete the access token itself."
|
25
|
+
say "You can sign in again with `envirobly signin`."
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "set_default_account", "Choose default account to deploy the current project to"
|
29
|
+
def set_default_account
|
30
|
+
Envirobly::Defaults::Account.new(shell:).require_id
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "set_default_region", "Set default region for the current project when deploying for the first time"
|
34
|
+
def set_default_region
|
35
|
+
Envirobly::Defaults::Region.new(shell:).require_id
|
36
|
+
end
|
37
|
+
|
12
38
|
desc "validate", "Validates config"
|
13
39
|
def validate
|
14
|
-
|
40
|
+
Envirobly::AccessToken.new(shell:).require!
|
41
|
+
|
42
|
+
configs = Envirobly::Config.new
|
15
43
|
api = Envirobly::Api.new
|
16
44
|
|
17
45
|
params = { validation: configs.to_params }
|
18
46
|
response = api.validate_shape params
|
19
47
|
|
20
48
|
if response.object.fetch("valid")
|
21
|
-
puts "
|
49
|
+
puts "Config is valid #{green_check}"
|
22
50
|
else
|
23
|
-
response.object.fetch("errors")
|
24
|
-
puts "#{config_path}:"
|
25
|
-
puts
|
26
|
-
messages.each_with_index do |message, index|
|
27
|
-
puts " #{message}"
|
28
|
-
puts
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
51
|
+
display_config_errors response.object.fetch("errors")
|
32
52
|
exit 1
|
33
53
|
end
|
34
54
|
end
|
35
55
|
|
36
56
|
desc "deploy [ENVIRON_NAME]", <<~TXT
|
37
|
-
Deploy to
|
38
|
-
|
57
|
+
Deploy to environ identified by name.
|
58
|
+
Name can contain letters, numbers, dashes or underscores.
|
59
|
+
If environ name is left blank, current git branch name is used.
|
39
60
|
TXT
|
61
|
+
method_option :account_id, type: :numeric
|
62
|
+
method_option :region, type: :string
|
63
|
+
method_option :project, type: :string
|
40
64
|
method_option :commit, type: :string, default: "HEAD"
|
41
65
|
method_option :dry_run, type: :boolean, default: false
|
42
|
-
|
43
|
-
|
44
|
-
method_option :project_region, type: :string
|
45
|
-
def deploy(environ_name = Envirobly::Git.new.current_branch)
|
46
|
-
deployment = Envirobly::Deployment.new(
|
47
|
-
environ_name:,
|
48
|
-
commit_ref: options.commit,
|
49
|
-
account_id: options.account_id,
|
50
|
-
project_name: options.project_name,
|
51
|
-
project_region: options.project_region
|
52
|
-
)
|
53
|
-
deployment.perform(dry_run: options.dry_run)
|
54
|
-
end
|
55
|
-
|
56
|
-
desc "set_access_token TOKEN", "Save and use an access token generated at Envirobly"
|
57
|
-
def set_access_token
|
58
|
-
token = ask("Access Token:", echo: false).strip
|
66
|
+
def deploy(environ_name = nil)
|
67
|
+
commit = Envirobly::Git::Commit.new options.commit
|
59
68
|
|
60
|
-
|
61
|
-
|
62
|
-
$stderr.puts "Token can't be empty."
|
69
|
+
unless commit.exists?
|
70
|
+
say_error "Commit '#{commit.ref}' doesn't exist in this repository. Aborting."
|
63
71
|
exit 1
|
64
72
|
end
|
65
73
|
|
66
|
-
Envirobly::AccessToken.new(
|
67
|
-
|
74
|
+
Envirobly::AccessToken.new(shell:).require!
|
75
|
+
|
76
|
+
environ_name = environ_name.presence || commit.current_branch
|
77
|
+
project_name = nil
|
78
|
+
project_id = nil
|
79
|
+
|
80
|
+
if options.project.present?
|
81
|
+
if options.project =~ Envirobly::Defaults::Project.regexp
|
82
|
+
project_id = $1.to_i
|
83
|
+
else
|
84
|
+
project_name = options.project
|
85
|
+
end
|
86
|
+
end
|
68
87
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
88
|
+
deployment = Envirobly::Deployment.new(
|
89
|
+
account_id: options.account_id,
|
90
|
+
region: options.region,
|
91
|
+
project_name:,
|
92
|
+
environ_name:,
|
93
|
+
project_id:,
|
94
|
+
commit:,
|
95
|
+
shell:
|
96
|
+
)
|
97
|
+
deployment.perform(dry_run: options.dry_run)
|
74
98
|
end
|
75
99
|
|
76
|
-
desc "pull", "Download
|
100
|
+
desc "pull", "Download build context"
|
77
101
|
def pull(region, bucket, ref, path)
|
78
102
|
Envirobly::Duration.measure("Build context download took %s") do
|
79
103
|
s3 = Envirobly::Aws::S3.new(region:, bucket:)
|
80
104
|
s3.pull ref, path
|
81
105
|
end
|
82
106
|
end
|
83
|
-
|
84
|
-
desc "object_tree", "Show object tree used for deployments"
|
85
|
-
method_option :commit, type: :string, default: "HEAD"
|
86
|
-
def object_tree
|
87
|
-
commit = Envirobly::Git::Commit.new options.commit
|
88
|
-
puts "Commit: #{commit.ref}"
|
89
|
-
pp commit.object_tree
|
90
|
-
puts "SHA256: #{commit.object_tree_checksum}"
|
91
|
-
end
|
92
|
-
|
93
|
-
desc "measure", "POC of Envirobly::Duration"
|
94
|
-
def measure
|
95
|
-
Envirobly::Duration.measure do
|
96
|
-
print "Doing something for 2s"
|
97
|
-
sleep 2
|
98
|
-
end
|
99
|
-
|
100
|
-
Envirobly::Duration.measure do
|
101
|
-
print "Doing something else for 100ms"
|
102
|
-
sleep 0.1
|
103
|
-
end
|
104
|
-
|
105
|
-
Envirobly::Duration.measure("Custom message, took %s") do
|
106
|
-
puts "Sleeping 2.5s with custom message"
|
107
|
-
sleep 2.5
|
108
|
-
end
|
109
|
-
|
110
|
-
puts "Done."
|
111
|
-
end
|
112
107
|
end
|
data/lib/envirobly/colorize.rb
CHANGED
@@ -11,6 +11,10 @@ module Envirobly::Colorize
|
|
11
11
|
[ FAINT, text, RESET ].join
|
12
12
|
end
|
13
13
|
|
14
|
+
def bold(text)
|
15
|
+
[ BOLD, text, RESET ].join
|
16
|
+
end
|
17
|
+
|
14
18
|
def green(text)
|
15
19
|
[ GREEN, text, RESET ].join
|
16
20
|
end
|
@@ -18,4 +22,33 @@ module Envirobly::Colorize
|
|
18
22
|
def yellow(text)
|
19
23
|
[ YELLOW, text, RESET ].join
|
20
24
|
end
|
25
|
+
|
26
|
+
def red(text)
|
27
|
+
[ RED, text, RESET ].join
|
28
|
+
end
|
29
|
+
|
30
|
+
def green_check
|
31
|
+
green("✔")
|
32
|
+
end
|
33
|
+
|
34
|
+
def downwards_arrow_to_right
|
35
|
+
"↳"
|
36
|
+
end
|
37
|
+
|
38
|
+
def cross
|
39
|
+
"✖"
|
40
|
+
end
|
41
|
+
|
42
|
+
def display_config_errors(errors)
|
43
|
+
puts "#{red(cross)} Config contains the following issues:"
|
44
|
+
|
45
|
+
errors.each do |error|
|
46
|
+
puts
|
47
|
+
puts " #{error["message"]}"
|
48
|
+
|
49
|
+
if error["path"]
|
50
|
+
puts faint(" #{downwards_arrow_to_right} #{error["path"]}")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
21
54
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "dotenv"
|
2
|
+
|
3
|
+
class Envirobly::Config
|
4
|
+
DIR = ".envirobly"
|
5
|
+
BASE = "deploy.yml"
|
6
|
+
ENV_VARS = "env"
|
7
|
+
OVERRIDES_PATTERN = /deploy\.([a-z0-9\-_]+)\.yml/i
|
8
|
+
|
9
|
+
def initialize(dir = DIR)
|
10
|
+
@dir = Pathname.new dir
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_params
|
14
|
+
{
|
15
|
+
configs:,
|
16
|
+
env_vars:
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def configs
|
22
|
+
Dir.entries(@dir).map do |file|
|
23
|
+
path = File.join(@dir, file)
|
24
|
+
|
25
|
+
next unless File.file?(path) && config_file?(file)
|
26
|
+
|
27
|
+
[ "#{DIR}/#{file}", File.read(path) ]
|
28
|
+
end.compact.to_h
|
29
|
+
end
|
30
|
+
|
31
|
+
def env_vars
|
32
|
+
Dotenv.parse @dir.join(ENV_VARS)
|
33
|
+
end
|
34
|
+
|
35
|
+
def config_file?(file)
|
36
|
+
file == BASE || file.match?(OVERRIDES_PATTERN)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class Envirobly::Default
|
2
|
+
attr_accessor :shell
|
3
|
+
|
4
|
+
def self.key = "url"
|
5
|
+
|
6
|
+
def initialize(shell: nil)
|
7
|
+
@path = File.join Envirobly::Config::DIR, "defaults", self.class.file
|
8
|
+
@shell = shell
|
9
|
+
end
|
10
|
+
|
11
|
+
def id
|
12
|
+
if File.exist?(@path)
|
13
|
+
content = YAML.safe_load_file(@path)
|
14
|
+
|
15
|
+
if content[self.class.key] =~ self.class.regexp
|
16
|
+
return cast_id($1)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def save(url)
|
24
|
+
unless url =~ self.class.regexp
|
25
|
+
raise ArgumentError, "'#{url}' must match #{self.class.regexp}"
|
26
|
+
end
|
27
|
+
|
28
|
+
FileUtils.mkdir_p(File.dirname(@path))
|
29
|
+
content = YAML.dump({ self.class.key => url })
|
30
|
+
File.write(@path, content)
|
31
|
+
end
|
32
|
+
|
33
|
+
def save_if_none(url)
|
34
|
+
return if id.present?
|
35
|
+
|
36
|
+
save(url)
|
37
|
+
end
|
38
|
+
|
39
|
+
def require_if_none
|
40
|
+
id || require_id
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def cast_id(value)
|
45
|
+
value.to_i
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Envirobly::Defaults::Account < Envirobly::Default
|
2
|
+
include Envirobly::Colorize
|
3
|
+
|
4
|
+
def self.file = "account.yml"
|
5
|
+
def self.regexp = /accounts\/(\d+)/
|
6
|
+
|
7
|
+
def require_id
|
8
|
+
api = Envirobly::Api.new
|
9
|
+
accounts = api.list_accounts
|
10
|
+
|
11
|
+
if accounts.object.blank?
|
12
|
+
shell.say_error "Please connect an AWS account to your Envirobly account first."
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
|
16
|
+
account = accounts.object.first
|
17
|
+
id = account["id"]
|
18
|
+
|
19
|
+
if accounts.object.size > 1
|
20
|
+
puts "Choose default account to deploy this project to:"
|
21
|
+
|
22
|
+
data = [ [ "ID", "Name", "AWS number", "URL" ] ] +
|
23
|
+
accounts.object.pluck("id", "name", "aws_id", "url")
|
24
|
+
|
25
|
+
shell.print_table data, borders: true
|
26
|
+
|
27
|
+
limited_to = accounts.object.pluck("id").map(&:to_s)
|
28
|
+
|
29
|
+
begin
|
30
|
+
id = shell.ask("Type in the account ID:", limited_to:).to_i
|
31
|
+
rescue Interrupt
|
32
|
+
shell.say_error "Cancelled"
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
|
36
|
+
account = accounts.object.find { |a| a["id"] == id }
|
37
|
+
end
|
38
|
+
|
39
|
+
save account["url"]
|
40
|
+
|
41
|
+
shell.say "Account ##{id} set as project default "
|
42
|
+
shell.say green_check
|
43
|
+
|
44
|
+
id
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class Envirobly::Defaults::Region < Envirobly::Default
|
2
|
+
include Envirobly::Colorize
|
3
|
+
|
4
|
+
def self.file = "region.yml"
|
5
|
+
def self.regexp = /([a-z0-9\-)]+)/
|
6
|
+
def self.key = "code"
|
7
|
+
|
8
|
+
def require_id
|
9
|
+
api = Envirobly::Api.new
|
10
|
+
response = api.list_regions
|
11
|
+
|
12
|
+
shell.say "Choose default project region to deploy to:"
|
13
|
+
shell.print_table [ [ "Name", "Location", "Group" ] ] +
|
14
|
+
response.object.pluck("code", "title", "group_title"), borders: true
|
15
|
+
|
16
|
+
code = nil
|
17
|
+
limited_to = response.object.pluck("code")
|
18
|
+
|
19
|
+
while code.nil?
|
20
|
+
begin
|
21
|
+
code = shell.ask("Type in the region name:", default: "us-east-1")
|
22
|
+
rescue Interrupt
|
23
|
+
shell.say_error "Cancelled"
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
|
27
|
+
unless code.in?(limited_to)
|
28
|
+
shell.say_error "'#{code}' is not a supported region, please try again"
|
29
|
+
code = nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
save code
|
34
|
+
|
35
|
+
shell.say "Region '#{id}' set as project default "
|
36
|
+
shell.say green_check
|
37
|
+
|
38
|
+
id
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def cast_id(value)
|
43
|
+
value
|
44
|
+
end
|
45
|
+
end
|
data/lib/envirobly/deployment.rb
CHANGED
@@ -3,24 +3,28 @@ require "yaml"
|
|
3
3
|
class Envirobly::Deployment
|
4
4
|
include Envirobly::Colorize
|
5
5
|
|
6
|
-
def initialize(environ_name:,
|
6
|
+
def initialize(environ_name:, commit:, account_id:, project_name:, project_id:, region:, shell:)
|
7
7
|
@environ_name = environ_name
|
8
|
-
@commit =
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
@commit = commit
|
9
|
+
@config = Envirobly::Config.new
|
10
|
+
@default_account = Envirobly::Defaults::Account.new(shell:)
|
11
|
+
@default_project = Envirobly::Defaults::Project.new(shell:)
|
12
|
+
@default_region = Envirobly::Defaults::Region.new(shell:)
|
13
|
+
|
14
|
+
if account_id.blank?
|
15
|
+
account_id = @default_account.require_if_none
|
13
16
|
end
|
14
17
|
|
15
|
-
|
18
|
+
if project_id.blank? && project_name.blank?
|
19
|
+
project_id = @default_project.id
|
16
20
|
|
17
|
-
|
18
|
-
|
21
|
+
if project_id.nil?
|
22
|
+
project_name = File.basename(Dir.pwd)
|
23
|
+
end
|
19
24
|
end
|
20
25
|
|
21
|
-
|
22
|
-
|
23
|
-
project_id = @configs.default_project_id
|
26
|
+
if region.blank?
|
27
|
+
region = @default_region.require_if_none
|
24
28
|
end
|
25
29
|
|
26
30
|
@params = {
|
@@ -30,7 +34,7 @@ class Envirobly::Deployment
|
|
30
34
|
project: {
|
31
35
|
id: project_id,
|
32
36
|
name: project_name,
|
33
|
-
region:
|
37
|
+
region:
|
34
38
|
},
|
35
39
|
deployment: {
|
36
40
|
environ_name:,
|
@@ -38,7 +42,7 @@ class Envirobly::Deployment
|
|
38
42
|
commit_time: @commit.time,
|
39
43
|
commit_message: @commit.message,
|
40
44
|
object_tree_checksum: @commit.object_tree_checksum,
|
41
|
-
**@
|
45
|
+
**@config.to_params
|
42
46
|
}
|
43
47
|
}
|
44
48
|
end
|
@@ -58,11 +62,18 @@ class Envirobly::Deployment
|
|
58
62
|
api = Envirobly::Api.new
|
59
63
|
|
60
64
|
Envirobly::Duration.measure do
|
61
|
-
print "Preparing project..."
|
62
65
|
response = api.create_deployment @params
|
63
66
|
|
64
|
-
|
65
|
-
|
67
|
+
unless response.success?
|
68
|
+
display_config_errors response.object.fetch("errors")
|
69
|
+
exit 1
|
70
|
+
end
|
71
|
+
|
72
|
+
print "Preparing project..."
|
73
|
+
|
74
|
+
@default_account.save_if_none response.object.fetch("account_url")
|
75
|
+
@default_project.save_if_none response.object.fetch("project_url")
|
76
|
+
@default_region.save_if_none response.object.fetch("region")
|
66
77
|
|
67
78
|
# Fetch credentials for build context upload
|
68
79
|
@deployment_url = response.object.fetch("url")
|
data/lib/envirobly/duration.rb
CHANGED
data/lib/envirobly/git/commit.rb
CHANGED
@@ -53,7 +53,7 @@ class Envirobly::Git::Commit < Envirobly::Git
|
|
53
53
|
git(%(ls-tree -r #{ref}), chdir:).stdout.lines.each do |line|
|
54
54
|
mode, type, object_hash, path = line.split(/\s+/)
|
55
55
|
|
56
|
-
next if path.start_with?("#{Envirobly::
|
56
|
+
next if path.start_with?("#{Envirobly::Config::DIR}/")
|
57
57
|
|
58
58
|
if type == "commit"
|
59
59
|
objects.merge! object_tree(ref: object_hash, chdir: File.join(chdir, path))
|
@@ -74,6 +74,6 @@ class Envirobly::Git::Commit < Envirobly::Git
|
|
74
74
|
# @deprecated
|
75
75
|
def objects_with_checksum_at(path)
|
76
76
|
git(%{ls-tree #{@ref} --format='%(objectname) %(path)' #{path}}).stdout.lines.map(&:chomp).
|
77
|
-
reject { _1.split(" ").last == Envirobly::
|
77
|
+
reject { _1.split(" ").last == Envirobly::Config::DIR }
|
78
78
|
end
|
79
79
|
end
|
data/lib/envirobly/version.rb
CHANGED
data/lib/envirobly.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: envirobly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Starsi
|
@@ -37,20 +37,6 @@ dependencies:
|
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '2.6'
|
40
|
-
- !ruby/object:Gem::Dependency
|
41
|
-
name: ostruct
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - "~>"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: 0.1.0
|
47
|
-
type: :runtime
|
48
|
-
prerelease: false
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: 0.1.0
|
54
40
|
- !ruby/object:Gem::Dependency
|
55
41
|
name: aws-sdk-s3
|
56
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,75 +80,75 @@ dependencies:
|
|
94
80
|
- !ruby/object:Gem::Version
|
95
81
|
version: '3.1'
|
96
82
|
- !ruby/object:Gem::Dependency
|
97
|
-
name:
|
83
|
+
name: activesupport
|
98
84
|
requirement: !ruby/object:Gem::Requirement
|
99
85
|
requirements:
|
100
|
-
- - "
|
86
|
+
- - "~>"
|
101
87
|
- !ruby/object:Gem::Version
|
102
|
-
version: '0'
|
103
|
-
type: :
|
88
|
+
version: '8.0'
|
89
|
+
type: :runtime
|
104
90
|
prerelease: false
|
105
91
|
version_requirements: !ruby/object:Gem::Requirement
|
106
92
|
requirements:
|
107
|
-
- - "
|
93
|
+
- - "~>"
|
108
94
|
- !ruby/object:Gem::Version
|
109
|
-
version: '0'
|
95
|
+
version: '8.0'
|
110
96
|
- !ruby/object:Gem::Dependency
|
111
|
-
name:
|
97
|
+
name: debug
|
112
98
|
requirement: !ruby/object:Gem::Requirement
|
113
99
|
requirements:
|
114
|
-
- - "
|
100
|
+
- - "~>"
|
115
101
|
- !ruby/object:Gem::Version
|
116
|
-
version: '
|
102
|
+
version: '1.10'
|
117
103
|
type: :development
|
118
104
|
prerelease: false
|
119
105
|
version_requirements: !ruby/object:Gem::Requirement
|
120
106
|
requirements:
|
121
|
-
- - "
|
107
|
+
- - "~>"
|
122
108
|
- !ruby/object:Gem::Version
|
123
|
-
version: '
|
109
|
+
version: '1.10'
|
124
110
|
- !ruby/object:Gem::Dependency
|
125
|
-
name:
|
111
|
+
name: minitest
|
126
112
|
requirement: !ruby/object:Gem::Requirement
|
127
113
|
requirements:
|
128
|
-
- - "
|
114
|
+
- - "~>"
|
129
115
|
- !ruby/object:Gem::Version
|
130
|
-
version: '
|
116
|
+
version: '5.25'
|
131
117
|
type: :development
|
132
118
|
prerelease: false
|
133
119
|
version_requirements: !ruby/object:Gem::Requirement
|
134
120
|
requirements:
|
135
|
-
- - "
|
121
|
+
- - "~>"
|
136
122
|
- !ruby/object:Gem::Version
|
137
|
-
version: '
|
123
|
+
version: '5.25'
|
138
124
|
- !ruby/object:Gem::Dependency
|
139
|
-
name:
|
125
|
+
name: mocha
|
140
126
|
requirement: !ruby/object:Gem::Requirement
|
141
127
|
requirements:
|
142
|
-
- - "
|
128
|
+
- - "~>"
|
143
129
|
- !ruby/object:Gem::Version
|
144
|
-
version: '
|
130
|
+
version: '2.7'
|
145
131
|
type: :development
|
146
132
|
prerelease: false
|
147
133
|
version_requirements: !ruby/object:Gem::Requirement
|
148
134
|
requirements:
|
149
|
-
- - "
|
135
|
+
- - "~>"
|
150
136
|
- !ruby/object:Gem::Version
|
151
|
-
version: '
|
137
|
+
version: '2.7'
|
152
138
|
- !ruby/object:Gem::Dependency
|
153
139
|
name: railties
|
154
140
|
requirement: !ruby/object:Gem::Requirement
|
155
141
|
requirements:
|
156
|
-
- - "
|
142
|
+
- - "~>"
|
157
143
|
- !ruby/object:Gem::Version
|
158
|
-
version: '0'
|
144
|
+
version: '8.0'
|
159
145
|
type: :development
|
160
146
|
prerelease: false
|
161
147
|
version_requirements: !ruby/object:Gem::Requirement
|
162
148
|
requirements:
|
163
|
-
- - "
|
149
|
+
- - "~>"
|
164
150
|
- !ruby/object:Gem::Version
|
165
|
-
version: '0'
|
151
|
+
version: '8.0'
|
166
152
|
email: klevo@klevo.sk
|
167
153
|
executables:
|
168
154
|
- envirobly
|
@@ -171,7 +157,6 @@ extra_rdoc_files: []
|
|
171
157
|
files:
|
172
158
|
- LICENSE
|
173
159
|
- bin/envirobly
|
174
|
-
- lib/core_ext.rb
|
175
160
|
- lib/envirobly.rb
|
176
161
|
- lib/envirobly/access_token.rb
|
177
162
|
- lib/envirobly/api.rb
|
@@ -182,7 +167,12 @@ files:
|
|
182
167
|
- lib/envirobly/cli.rb
|
183
168
|
- lib/envirobly/cli/main.rb
|
184
169
|
- lib/envirobly/colorize.rb
|
185
|
-
- lib/envirobly/
|
170
|
+
- lib/envirobly/config.rb
|
171
|
+
- lib/envirobly/default.rb
|
172
|
+
- lib/envirobly/defaults.rb
|
173
|
+
- lib/envirobly/defaults/account.rb
|
174
|
+
- lib/envirobly/defaults/project.rb
|
175
|
+
- lib/envirobly/defaults/region.rb
|
186
176
|
- lib/envirobly/deployment.rb
|
187
177
|
- lib/envirobly/duration.rb
|
188
178
|
- lib/envirobly/git.rb
|
@@ -200,14 +190,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
200
190
|
requirements:
|
201
191
|
- - ">="
|
202
192
|
- !ruby/object:Gem::Version
|
203
|
-
version: '
|
193
|
+
version: '3.2'
|
204
194
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
205
195
|
requirements:
|
206
196
|
- - ">="
|
207
197
|
- !ruby/object:Gem::Version
|
208
198
|
version: '0'
|
209
199
|
requirements: []
|
210
|
-
rubygems_version: 3.6.
|
200
|
+
rubygems_version: 3.6.8
|
211
201
|
specification_version: 4
|
212
202
|
summary: Envirobly command line interface
|
213
203
|
test_files: []
|
data/lib/core_ext.rb
DELETED
@@ -1,113 +0,0 @@
|
|
1
|
-
class Array
|
2
|
-
alias_method :blank?, :empty?
|
3
|
-
|
4
|
-
def present?
|
5
|
-
!empty?
|
6
|
-
end
|
7
|
-
|
8
|
-
def second
|
9
|
-
self[1]
|
10
|
-
end
|
11
|
-
|
12
|
-
def third
|
13
|
-
self[2]
|
14
|
-
end
|
15
|
-
|
16
|
-
def fourth
|
17
|
-
self[3]
|
18
|
-
end
|
19
|
-
|
20
|
-
def fifth
|
21
|
-
self[4]
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
class Object
|
26
|
-
def blank?
|
27
|
-
respond_to?(:empty?) ? !!empty? : false
|
28
|
-
end
|
29
|
-
|
30
|
-
def present?
|
31
|
-
!blank?
|
32
|
-
end
|
33
|
-
|
34
|
-
def presence
|
35
|
-
self if present?
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
class NilClass
|
40
|
-
def blank?
|
41
|
-
true
|
42
|
-
end
|
43
|
-
|
44
|
-
def present?
|
45
|
-
false
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
class FalseClass
|
50
|
-
def blank?
|
51
|
-
true
|
52
|
-
end
|
53
|
-
|
54
|
-
def present?
|
55
|
-
false
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
class TrueClass
|
60
|
-
def blank?
|
61
|
-
false
|
62
|
-
end
|
63
|
-
|
64
|
-
def present?
|
65
|
-
true
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
class Hash
|
70
|
-
alias_method :blank?, :empty?
|
71
|
-
|
72
|
-
def present?
|
73
|
-
!empty?
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
class Symbol
|
78
|
-
alias_method :blank?, :empty?
|
79
|
-
|
80
|
-
def present?
|
81
|
-
!empty?
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
class String
|
86
|
-
def blank?
|
87
|
-
strip.empty?
|
88
|
-
end
|
89
|
-
|
90
|
-
def present?
|
91
|
-
!blank?
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
class Numeric
|
96
|
-
def blank?
|
97
|
-
false
|
98
|
-
end
|
99
|
-
|
100
|
-
def present?
|
101
|
-
true
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
class Time
|
106
|
-
def blank?
|
107
|
-
false
|
108
|
-
end
|
109
|
-
|
110
|
-
def present?
|
111
|
-
true
|
112
|
-
end
|
113
|
-
end
|
data/lib/envirobly/configs.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
require "dotenv"
|
2
|
-
|
3
|
-
class Envirobly::Configs
|
4
|
-
DIR = ".envirobly"
|
5
|
-
ENV = "env"
|
6
|
-
BASE = "deploy.yml"
|
7
|
-
OVERRIDES_PATTERN = /deploy\.([a-z0-9\-_]+)\.yml/i
|
8
|
-
DEFAULTS_DIR = File.join DIR, "defaults"
|
9
|
-
DEFAULT_ACCOUNT_PATH = File.join(DEFAULTS_DIR, "account.yml")
|
10
|
-
DEFAULT_PROJECT_PATH = File.join(DEFAULTS_DIR, "project.yml")
|
11
|
-
|
12
|
-
def initialize(dir = DIR)
|
13
|
-
@dir = Pathname.new dir
|
14
|
-
end
|
15
|
-
|
16
|
-
def to_params
|
17
|
-
{
|
18
|
-
configs:,
|
19
|
-
env_vars:
|
20
|
-
}
|
21
|
-
end
|
22
|
-
|
23
|
-
def default_project_id
|
24
|
-
if File.exist?(DEFAULT_PROJECT_PATH)
|
25
|
-
content = YAML.safe_load_file(DEFAULT_PROJECT_PATH)
|
26
|
-
if content["url"] =~ /projects\/(\d+)/
|
27
|
-
return $1.to_i
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
nil
|
32
|
-
end
|
33
|
-
|
34
|
-
def default_account_id
|
35
|
-
if File.exist?(DEFAULT_ACCOUNT_PATH)
|
36
|
-
content = YAML.safe_load_file(DEFAULT_ACCOUNT_PATH)
|
37
|
-
if content["url"] =~ /accounts\/(\d+)/
|
38
|
-
return $1.to_i
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
nil
|
43
|
-
end
|
44
|
-
|
45
|
-
def save_default_account(url)
|
46
|
-
return if File.exist?(DEFAULT_ACCOUNT_PATH)
|
47
|
-
|
48
|
-
FileUtils.mkdir_p(DEFAULTS_DIR)
|
49
|
-
content = YAML.dump({ "url" => url })
|
50
|
-
File.write(DEFAULT_ACCOUNT_PATH, content)
|
51
|
-
end
|
52
|
-
|
53
|
-
def save_default_project(url)
|
54
|
-
return if File.exist?(DEFAULT_PROJECT_PATH)
|
55
|
-
|
56
|
-
FileUtils.mkdir_p(DEFAULTS_DIR)
|
57
|
-
content = YAML.dump({ "url" => url })
|
58
|
-
File.write(DEFAULT_PROJECT_PATH, content)
|
59
|
-
end
|
60
|
-
|
61
|
-
private
|
62
|
-
def configs
|
63
|
-
Dir.entries(@dir).map do |file|
|
64
|
-
path = File.join(@dir, file)
|
65
|
-
|
66
|
-
next unless File.file?(path) && config_file?(file)
|
67
|
-
|
68
|
-
[ "#{DIR}/#{file}", File.read(path) ]
|
69
|
-
end.compact.to_h
|
70
|
-
end
|
71
|
-
|
72
|
-
def env_vars
|
73
|
-
Dotenv.parse @dir.join(ENV)
|
74
|
-
end
|
75
|
-
|
76
|
-
def config_file?(file)
|
77
|
-
file == BASE || file.match?(OVERRIDES_PATTERN)
|
78
|
-
end
|
79
|
-
end
|