envirobly 0.4.2 → 0.5.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/core_ext.rb +113 -0
- data/lib/envirobly/api.rb +1 -1
- data/lib/envirobly/aws/credentials.rb +3 -3
- data/lib/envirobly/cli/main.rb +1 -0
- data/lib/envirobly/config.rb +71 -37
- data/lib/envirobly/deployment.rb +22 -44
- data/lib/envirobly/git/commit.rb +39 -5
- data/lib/envirobly/version.rb +1 -1
- data/lib/envirobly.rb +2 -2
- metadata +64 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aefc0201069c2ebcf4e9038a80904d7e3c6b3217a582572db2536cf9f877367e
|
4
|
+
data.tar.gz: 26b791aa16c6c38613e7ef5b32cc8f1c93eb7342327ed52968e6ee345a9fa12f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5dd97f5d8c19a6e3690884f9f9fc9803a338db2048aaf96a9e5502f68f1d70890a1906f5a478dc998b78e39874cce3db600411a71ee615b41276d63dccdf8c4
|
7
|
+
data.tar.gz: fe25c4413c314d7368e7fe6b0b05c44f3919159421b75a6511c1ee5c3ba3174ca8c5e3dc52628cd485556a1ef81e92cb2116549573b3d843ed1f753df3ba337b
|
data/lib/core_ext.rb
ADDED
@@ -0,0 +1,113 @@
|
|
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/api.rb
CHANGED
@@ -5,9 +5,9 @@ class Envirobly::Aws::Credentials
|
|
5
5
|
|
6
6
|
def as_env_vars
|
7
7
|
[
|
8
|
-
%
|
9
|
-
%
|
10
|
-
%
|
8
|
+
%(AWS_ACCESS_KEY_ID="#{@params.fetch("access_key_id")}"),
|
9
|
+
%(AWS_SECRET_ACCESS_KEY="#{@params.fetch("secret_access_key")}"),
|
10
|
+
%(AWS_SESSION_TOKEN="#{@params.fetch("session_token")}")
|
11
11
|
]
|
12
12
|
end
|
13
13
|
|
data/lib/envirobly/cli/main.rb
CHANGED
@@ -6,6 +6,7 @@ class Envirobly::Cli::Main < Envirobly::Base
|
|
6
6
|
|
7
7
|
desc "deploy ENVIRONMENT", "Deploy to environment identified by name or URL"
|
8
8
|
method_option :commit, type: :string, default: "HEAD"
|
9
|
+
method_option :dry_run, type: :boolean, default: false
|
9
10
|
def deploy(environment)
|
10
11
|
abort_if_aws_cli_is_missing
|
11
12
|
Envirobly::Deployment.new environment, options
|
data/lib/envirobly/config.rb
CHANGED
@@ -6,76 +6,110 @@ class Envirobly::Config
|
|
6
6
|
DIR = ".envirobly"
|
7
7
|
PATH = "#{DIR}/project.yml"
|
8
8
|
|
9
|
-
attr_reader :
|
9
|
+
attr_reader :errors, :result, :raw
|
10
10
|
|
11
11
|
def initialize(commit)
|
12
12
|
@commit = commit
|
13
|
-
@
|
14
|
-
@
|
15
|
-
|
16
|
-
|
17
|
-
transform_env_var_values!
|
18
|
-
append_image_tags!
|
19
|
-
end
|
13
|
+
@errors = []
|
14
|
+
@result = nil
|
15
|
+
@project_url = nil
|
16
|
+
@raw = @commit.file_content PATH
|
20
17
|
end
|
21
18
|
|
22
19
|
def dig(*args)
|
23
|
-
@project.dig
|
20
|
+
@project.dig(*args)
|
24
21
|
rescue NoMethodError
|
25
22
|
nil
|
26
23
|
end
|
27
24
|
|
28
|
-
def
|
29
|
-
@
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
25
|
+
def compile(environment = nil)
|
26
|
+
@environment = environment
|
27
|
+
return unless @project = parse
|
28
|
+
set_project_url
|
29
|
+
merge_environment_overrides! unless @environment.nil?
|
30
|
+
transform_env_var_values!
|
31
|
+
append_image_tags!
|
32
|
+
@result = @project.slice(:services)
|
34
33
|
end
|
35
34
|
|
36
|
-
def
|
37
|
-
|
35
|
+
def to_deployment_params
|
36
|
+
{
|
37
|
+
environ: {
|
38
|
+
logical_id: @environment,
|
39
|
+
project_url: @project_url
|
40
|
+
},
|
41
|
+
commit: {
|
42
|
+
ref: @commit.ref,
|
43
|
+
time: @commit.time,
|
44
|
+
message: @commit.message
|
45
|
+
},
|
46
|
+
config: @result,
|
47
|
+
raw_config: @raw
|
48
|
+
}
|
38
49
|
end
|
39
50
|
|
40
51
|
private
|
41
|
-
def
|
42
|
-
YAML.
|
52
|
+
def parse
|
53
|
+
YAML.safe_load @raw, aliases: true, symbolize_names: true
|
43
54
|
rescue Psych::Exception => exception
|
44
|
-
@
|
55
|
+
@errors << exception.message
|
45
56
|
nil
|
46
57
|
end
|
47
58
|
|
48
|
-
def
|
49
|
-
|
59
|
+
def set_project_url
|
60
|
+
@project_url = dig :remote, :origin
|
61
|
+
if @project_url.blank?
|
62
|
+
@errors << "Missing a `remote.origin` link to project."
|
63
|
+
end
|
50
64
|
end
|
51
65
|
|
52
66
|
def transform_env_var_values!
|
53
|
-
@project.fetch(
|
54
|
-
service.fetch(
|
55
|
-
if value.is_a?(Hash) && value.has_key?(
|
56
|
-
@project[
|
67
|
+
@project.fetch(:services, {}).each do |logical_id, service|
|
68
|
+
service.fetch(:env, {}).each do |key, value|
|
69
|
+
if value.is_a?(Hash) && value.has_key?(:file)
|
70
|
+
@project[:services][logical_id][:env][key] = @commit.file_content(value.fetch(:file)).strip
|
57
71
|
end
|
58
72
|
end
|
59
73
|
end
|
60
74
|
end
|
61
75
|
|
62
76
|
NON_BUILDABLE_TYPES = %w[ postgres mysql valkey ]
|
77
|
+
BUILD_DEFAULTS = {
|
78
|
+
dockerfile: "Dockerfile",
|
79
|
+
build_context: "."
|
80
|
+
}
|
63
81
|
def append_image_tags!
|
64
|
-
@project.fetch(
|
65
|
-
next if NON_BUILDABLE_TYPES.include?(service[
|
82
|
+
@project.fetch(:services, {}).each do |logical_id, service|
|
83
|
+
next if NON_BUILDABLE_TYPES.include?(service[:type]) || service[:image].present?
|
84
|
+
checksums = []
|
66
85
|
|
67
|
-
|
68
|
-
|
86
|
+
BUILD_DEFAULTS.each do |attribute, default|
|
87
|
+
value = service.fetch(attribute, default)
|
88
|
+
checksum = @commit.objects_with_checksum_at value
|
89
|
+
if checksum.empty?
|
90
|
+
@errors << "Service `#{logical_id}` specifies `#{attribute}` as `#{value}` which doesn't exist in this commit."
|
91
|
+
else
|
92
|
+
checksums << checksum
|
93
|
+
end
|
94
|
+
end
|
69
95
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
].to_json
|
96
|
+
if checksums.size == 2
|
97
|
+
@project[:services][logical_id][:image_tag] = Digest::SHA1.hexdigest checksums.to_json
|
98
|
+
end
|
74
99
|
end
|
75
100
|
end
|
76
101
|
|
77
|
-
def
|
78
|
-
|
79
|
-
|
102
|
+
def merge_environment_overrides!
|
103
|
+
return unless services = @project.dig(:environments, @environment.to_sym)
|
104
|
+
services.each do |logical_id, service|
|
105
|
+
service.each do |attribute, value|
|
106
|
+
if value.is_a?(Hash) && @project[:services][logical_id][attribute].is_a?(Hash)
|
107
|
+
@project[:services][logical_id][attribute].merge! value
|
108
|
+
@project[:services][logical_id][attribute].compact!
|
109
|
+
else
|
110
|
+
@project[:services][logical_id][attribute] = value
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
80
114
|
end
|
81
115
|
end
|
data/lib/envirobly/deployment.rb
CHANGED
@@ -1,71 +1,49 @@
|
|
1
1
|
class Envirobly::Deployment
|
2
|
-
URL_MATCHER = /^https:\/\/envirobly\.(test|com)\/(\d+)\/environs\/(\d+)$/
|
3
|
-
|
4
2
|
def initialize(environment, options)
|
5
|
-
|
3
|
+
commit = Envirobly::Git::Commit.new options.commit
|
6
4
|
|
7
|
-
unless
|
5
|
+
unless commit.exists?
|
8
6
|
$stderr.puts "Commit #{options.commit} doesn't exist in this repository. Aborting."
|
9
7
|
exit 1
|
10
8
|
end
|
11
9
|
|
12
|
-
config = Envirobly::Config.new(
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
config = Envirobly::Config.new(commit)
|
11
|
+
config.compile(environment)
|
12
|
+
|
13
|
+
if config.errors.any?
|
14
|
+
$stderr.puts "Errors found while parsing #{Envirobly::Config::PATH}:"
|
15
|
+
$stderr.puts
|
16
|
+
config.errors.each do |error|
|
17
|
+
$stderr.puts " - #{error}"
|
18
|
+
end
|
19
|
+
$stderr.puts
|
20
|
+
$stderr.puts "Please fix these, commit the changes and try again."
|
16
21
|
exit 1
|
17
22
|
end
|
18
23
|
|
19
|
-
params =
|
20
|
-
environ: {
|
21
|
-
logical_id: environment
|
22
|
-
},
|
23
|
-
commit: {
|
24
|
-
ref: @commit.ref,
|
25
|
-
time: @commit.time,
|
26
|
-
message: @commit.message
|
27
|
-
},
|
28
|
-
config: config.to_h
|
29
|
-
}
|
24
|
+
params = config.to_deployment_params
|
30
25
|
|
31
26
|
puts "Deployment config:"
|
32
27
|
puts params.to_yaml
|
33
28
|
|
34
|
-
|
35
|
-
if project_url = config.dig("remote", "origin")
|
36
|
-
params[:environ][:project_url] = project_url
|
37
|
-
else
|
38
|
-
$stderr.puts "{remote.origin} is required in .envirobly/project.yml"
|
39
|
-
exit 1
|
40
|
-
end
|
41
|
-
end
|
29
|
+
exit if options.dry_run?
|
42
30
|
|
43
|
-
|
44
|
-
response =
|
31
|
+
api = Envirobly::Api.new
|
32
|
+
response = api.create_deployment params
|
45
33
|
deployment_url = response.object.fetch("url")
|
46
|
-
response =
|
47
|
-
|
48
|
-
|
34
|
+
response = api.get_deployment_with_delay_and_retry deployment_url
|
35
|
+
credentials = Envirobly::Aws::Credentials.new response.object.fetch("credentials")
|
36
|
+
bucket = response.object.fetch("bucket")
|
49
37
|
|
50
38
|
puts "Uploading build context, please wait..."
|
51
|
-
unless
|
39
|
+
unless commit.archive_and_upload(bucket:, credentials:)
|
52
40
|
$stderr.puts "Error exporting build context. Aborting."
|
53
41
|
exit 1
|
54
42
|
end
|
55
43
|
|
56
44
|
puts "Build context uploaded."
|
57
|
-
|
45
|
+
api.put_as_json deployment_url
|
58
46
|
|
59
47
|
# TODO: Output URL to watch the deployment progress
|
60
48
|
end
|
61
|
-
|
62
|
-
private
|
63
|
-
def archive_uri
|
64
|
-
"s3://#{@bucket}/#{@commit.ref}.tar.gz"
|
65
|
-
end
|
66
|
-
|
67
|
-
def archive_commit_and_upload
|
68
|
-
`git archive --format=tar.gz #{@commit.ref} | #{@credentials.as_inline_env_vars} aws s3 cp - #{archive_uri}`
|
69
|
-
$?.success?
|
70
|
-
end
|
71
49
|
end
|
data/lib/envirobly/git/commit.rb
CHANGED
@@ -1,23 +1,57 @@
|
|
1
1
|
require "time"
|
2
|
+
require "open3"
|
2
3
|
|
3
4
|
class Envirobly::Git::Commit
|
4
|
-
def initialize(ref)
|
5
|
+
def initialize(ref, working_dir: Dir.getwd)
|
5
6
|
@ref = ref
|
7
|
+
@working_dir = working_dir
|
6
8
|
end
|
7
9
|
|
8
10
|
def exists?
|
9
|
-
|
11
|
+
run(%(cat-file -t #{@ref})).strip == "commit"
|
10
12
|
end
|
11
13
|
|
12
14
|
def ref
|
13
|
-
@normalized_ref ||=
|
15
|
+
@normalized_ref ||= run(%(rev-parse #{@ref})).strip
|
14
16
|
end
|
15
17
|
|
16
18
|
def message
|
17
|
-
|
19
|
+
run(%(log #{@ref} -n1 --pretty=%B)).strip
|
18
20
|
end
|
19
21
|
|
20
22
|
def time
|
21
|
-
Time.parse
|
23
|
+
Time.parse run(%(log #{@ref} -n1 --date=iso --pretty=format:"%ad"))
|
22
24
|
end
|
25
|
+
|
26
|
+
def file_content(path)
|
27
|
+
run %(show #{@ref}:#{path})
|
28
|
+
end
|
29
|
+
|
30
|
+
def objects_with_checksum_at(path)
|
31
|
+
run(%{ls-tree #{@ref} --format='%(objectname) %(path)' #{path}}).lines.map(&:chomp).
|
32
|
+
reject { _1.split(" ").last == Envirobly::Config::DIR }
|
33
|
+
end
|
34
|
+
|
35
|
+
def archive_and_upload(bucket:, credentials:)
|
36
|
+
`GIT_WORK_TREE="#{@working_dir}" GIT_DIR="#{@working_dir}/.git" git archive --format=tar.gz #{ref} | #{credentials.as_inline_env_vars} aws s3 cp - #{archive_uri(bucket)}`
|
37
|
+
$?.success?
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def run(cmd)
|
42
|
+
@stdout = @stderr = @exit_code = @success = nil
|
43
|
+
full_cmd = %(GIT_WORK_TREE="#{@working_dir}" GIT_DIR="#{@working_dir}/.git" git #{cmd})
|
44
|
+
Open3.popen3(full_cmd) do |stdin, stdout, stderr, thread|
|
45
|
+
stdin.close
|
46
|
+
@stdout = stdout.read
|
47
|
+
@stderr = stderr.read
|
48
|
+
@exit_code = thread.value.exitstatus
|
49
|
+
@success = thread.value.success?
|
50
|
+
end
|
51
|
+
@stdout
|
52
|
+
end
|
53
|
+
|
54
|
+
def archive_uri(bucket)
|
55
|
+
"s3://#{bucket}/#{ref}.tar.gz"
|
56
|
+
end
|
23
57
|
end
|
data/lib/envirobly/version.rb
CHANGED
data/lib/envirobly.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: envirobly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Starsi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-09-
|
11
|
+
date: 2024-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -39,19 +39,75 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '2.6'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: ostruct
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
48
|
-
type: :
|
47
|
+
version: 0.1.0
|
48
|
+
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 0.1.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: debug
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activesupport
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: railties
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
55
111
|
description:
|
56
112
|
email: klevo@klevo.sk
|
57
113
|
executables:
|
@@ -61,6 +117,7 @@ extra_rdoc_files: []
|
|
61
117
|
files:
|
62
118
|
- LICENSE
|
63
119
|
- bin/envirobly
|
120
|
+
- lib/core_ext.rb
|
64
121
|
- lib/envirobly.rb
|
65
122
|
- lib/envirobly/access_token.rb
|
66
123
|
- lib/envirobly/api.rb
|
@@ -93,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
150
|
- !ruby/object:Gem::Version
|
94
151
|
version: '0'
|
95
152
|
requirements: []
|
96
|
-
rubygems_version: 3.5.
|
153
|
+
rubygems_version: 3.5.18
|
97
154
|
signing_key:
|
98
155
|
specification_version: 4
|
99
156
|
summary: Envirobly command line interface
|