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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1502f5b98c25be6da48fbdd5ebf525723d8985d4e45eef5693611a0aea9db82a
4
- data.tar.gz: 5684ae39ecb8f3f7006979e849a9746d17bb33dd849f8173836d2b9afa1cc6cb
3
+ metadata.gz: 9ef94e7e6db204bc73126d41dae8d3417e4ea7ac35e7cbecd5d496dcee842ee3
4
+ data.tar.gz: 32f53215e81d8e3d984cd7caf58fc0944c9636ba587e59dbd4573bfcd04f8a08
5
5
  SHA512:
6
- metadata.gz: 8273cfe4dddd1f1da589add660066d5bd2b3c70f1ff0df92f0461f9b4c0b416f99276cb1a69ea1e1f13529ab6e18aca9f3720bb5e3896f8403251ee58e935bfd
7
- data.tar.gz: a9e26055d4d0de16d449aec2ddc23921d61496969eb2ebd5812dc0279a8d2a1848c5e9ea074bfe5ea7c1f35c89af69162510ecfc88c5b8f7fa137c0241120c76
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
- def initialize(token = ENV.fetch("ENVIROBLY_ACCESS_TOKEN", nil))
6
- if token.nil? && File.exist?(access_token_path)
7
- @token = File.read(access_token_path)
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 config_root
15
- File.write access_token_path, @token
16
- File.chmod 0600, access_token_path
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
- private
25
- def config_root
26
- if ENV["XDG_CONFIG_HOME"]
27
- Pathname.new(ENV["XDG_CONFIG_HOME"]).join("envirobly")
28
- else
29
- Pathname.new(Dir.home).join(".envirobly")
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
- def access_token_path
34
- config_root.join "access_token"
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 = Envirobly::AccessToken.new
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 successful_response?(response)
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).tap do |response|
26
- unless successful_response?(response)
27
- $stderr.puts "Deployment creation request responded with #{response.code}. Aborting."
28
- # TODO: render 422 validation failed nicely
29
- $stderr.puts response.object
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
- MAX_RETRIES = 20
36
- RETRY_INTERVAL_SECONDS = 2
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 RETRY_INTERVAL_SECONDS * tries
40
+ sleep SHORT_RETRY_INTERVAL * tries
39
41
  response = get_as_json URI(url)
40
42
 
41
- if successful_response?(response)
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
- sleep RETRY_INTERVAL_SECONDS * tries
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
- URI::HTTPS.build(host: HOST, path: "/api/v1/shape_validations")
77
+ api_url_for "v1/shape_validations"
71
78
  end
72
79
 
73
80
  def api_v1_deployments_url
74
- URI::HTTPS.build(host: HOST, path: "/api/v1/deployments")
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
@@ -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
- configs = Envirobly::Configs.new
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 "All checks pass."
49
+ puts "Config is valid #{green_check}"
22
50
  else
23
- response.object.fetch("errors").each do |config_path, messages|
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 environment identified by name.
38
- When name is empty, current git branch name is used.
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
- method_option :account_id, type: :numeric
43
- method_option :project_name, type: :string
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
- if token.blank?
61
- $stderr.puts
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(token).save
67
- end
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
- desc "push", "Push commit manifest and blobs to S3"
70
- def push(region, bucket, ref = "HEAD")
71
- commit = Envirobly::Git::Commit.new ref
72
- s3 = Envirobly::Aws::S3.new(region:, bucket:)
73
- s3.push commit
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 working copy from S3"
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
@@ -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,4 @@
1
+ class Envirobly::Defaults::Project < Envirobly::Default
2
+ def self.file = "project.yml"
3
+ def self.regexp = /projects\/(\d+)/
4
+ 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
@@ -0,0 +1,2 @@
1
+ module Envirobly::Defaults
2
+ end
@@ -3,24 +3,28 @@ require "yaml"
3
3
  class Envirobly::Deployment
4
4
  include Envirobly::Colorize
5
5
 
6
- def initialize(environ_name:, commit_ref:, account_id:, project_name:, project_region:)
6
+ def initialize(environ_name:, commit:, account_id:, project_name:, project_id:, region:, shell:)
7
7
  @environ_name = environ_name
8
- @commit = Envirobly::Git::Commit.new commit_ref
9
-
10
- unless @commit.exists?
11
- $stderr.puts "Commit #{commit_ref} doesn't exist in this repository. Aborting."
12
- exit 1
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
- @configs = Envirobly::Configs.new
18
+ if project_id.blank? && project_name.blank?
19
+ project_id = @default_project.id
16
20
 
17
- if account_id.nil?
18
- account_id = @configs.default_account_id
21
+ if project_id.nil?
22
+ project_name = File.basename(Dir.pwd)
23
+ end
19
24
  end
20
25
 
21
- project_id = nil
22
- if project_name.nil?
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: project_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
- **@configs.to_params
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
- @configs.save_default_account(response.object.fetch("account_url"))
65
- @configs.save_default_project(response.object.fetch("project_url"))
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")
@@ -12,7 +12,7 @@ class Envirobly::Duration
12
12
  duration = format_duration(measurement)
13
13
 
14
14
  if message.nil?
15
- puts [ "", green("✔"), faint(duration) ].join(" ")
15
+ puts [ "", green_check, faint(duration) ].join(" ")
16
16
  else
17
17
  puts sprintf(message, duration)
18
18
  end
@@ -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::Configs::DIR}/")
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::Configs::DIR }
77
+ reject { _1.split(" ").last == Envirobly::Config::DIR }
78
78
  end
79
79
  end
@@ -1,3 +1,3 @@
1
1
  module Envirobly
2
- VERSION = "0.10.0"
2
+ VERSION = "1.0.0"
3
3
  end
data/lib/envirobly.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  module Envirobly
2
2
  end
3
3
 
4
+ require "active_support"
5
+ require "active_support/core_ext"
4
6
  require "zeitwerk"
5
- require "core_ext"
6
7
 
7
8
  loader = Zeitwerk::Loader.for_gem
8
- loader.ignore("#{__dir__}/core_ext.rb")
9
9
  loader.setup
10
10
  loader.eager_load
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.10.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: debug
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: :development
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: minitest
97
+ name: debug
112
98
  requirement: !ruby/object:Gem::Requirement
113
99
  requirements:
114
- - - ">="
100
+ - - "~>"
115
101
  - !ruby/object:Gem::Version
116
- version: '0'
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: '0'
109
+ version: '1.10'
124
110
  - !ruby/object:Gem::Dependency
125
- name: mocha
111
+ name: minitest
126
112
  requirement: !ruby/object:Gem::Requirement
127
113
  requirements:
128
- - - ">="
114
+ - - "~>"
129
115
  - !ruby/object:Gem::Version
130
- version: '0'
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: '0'
123
+ version: '5.25'
138
124
  - !ruby/object:Gem::Dependency
139
- name: activesupport
125
+ name: mocha
140
126
  requirement: !ruby/object:Gem::Requirement
141
127
  requirements:
142
- - - ">="
128
+ - - "~>"
143
129
  - !ruby/object:Gem::Version
144
- version: '0'
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: '0'
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/configs.rb
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: '0'
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.7
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
@@ -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