envirobly 0.5.2 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7cbc25ee0033c84e86fd94e67a3be65ee43c8fbcfd86cd962ecf9e5f616bf042
4
- data.tar.gz: e07002a42e3490bd841f6538ab7cd565990bf55e159fe8d7ce033cff62f6c38d
3
+ metadata.gz: 3e30e5017a85588ff1c6122ffb0a3fbb13b132793ca8a53a25b05e3402cdebc5
4
+ data.tar.gz: ff5049f4c3f9679586cfa6595ac52070eaaf8e10e34a9f96ec054a3df583e9c5
5
5
  SHA512:
6
- metadata.gz: eb490ba6309b3775f548522596c6a5d42504ba2ca878ef8c74b530af12733b9a9ac1ce016ece2afdb7d6c616f4121ca418a49ef3037e06790a9e3da3b916ba93
7
- data.tar.gz: 7abc4689844be2617b74bb425c0ba8136b793d5c0c36600d58defdeadf8a84e9b31715442467c1e912b8988ee1c708c61eedb0192a2af3eadf9fc0b54bf0a327
6
+ metadata.gz: d4aa3b80f59d1dbe19a045e802a36341d7b7393ec7320c9382fecbaa3f8182800b86b6b25bb1af02ff69badc3efb1fd200e2229314b20ed8960ed894f567d562
7
+ data.tar.gz: fa4076c20c3cda9c05a6c356ea125aec3879ce68b4448c6becda3448ce8cb8a37c0dc8525fa8f4f4fdd85161e01a18efaad78dde37bfc80b4e4ebe15b85d84f1
@@ -4,6 +4,25 @@ class Envirobly::Cli::Main < Envirobly::Base
4
4
  puts Envirobly::VERSION
5
5
  end
6
6
 
7
+ desc "validate", "Validates config"
8
+ def validate
9
+ commit = Envirobly::Git::Unstaged.new
10
+ config = Envirobly::Config.new(commit)
11
+ config.validate
12
+
13
+ if config.errors.any?
14
+ puts "Issues found validating `#{Envirobly::Config::PATH}`:"
15
+ puts
16
+ config.errors.each_with_index do |error, index|
17
+ puts " #{index + 1}. #{error}"
18
+ end
19
+ puts
20
+ exit 1
21
+ else
22
+ puts "All checks pass."
23
+ end
24
+ end
25
+
7
26
  desc "deploy ENVIRONMENT", "Deploy to environment identified by name or URL"
8
27
  method_option :commit, type: :string, default: "HEAD"
9
28
  method_option :dry_run, type: :boolean, default: false
@@ -15,7 +34,9 @@ class Envirobly::Cli::Main < Envirobly::Base
15
34
  desc "set_access_token TOKEN", "Save and use an access token generated at Envirobly"
16
35
  def set_access_token
17
36
  token = ask("Access Token:", echo: false).strip
18
- if token == ""
37
+
38
+ if token.blank?
39
+ $stderr.puts
19
40
  $stderr.puts "Token can't be empty."
20
41
  exit 1
21
42
  end
@@ -11,9 +11,10 @@ class Envirobly::Config
11
11
  def initialize(commit)
12
12
  @commit = commit
13
13
  @errors = []
14
- @result = nil
14
+ @result = {}
15
15
  @project_url = nil
16
16
  @raw = @commit.file_content PATH
17
+ @project = parse
17
18
  end
18
19
 
19
20
  def dig(*args)
@@ -22,14 +23,21 @@ class Envirobly::Config
22
23
  nil
23
24
  end
24
25
 
26
+ def validate
27
+ return unless @project
28
+ validate_top_level_keys
29
+ validate_services @project.fetch(:services)
30
+ validate_environments
31
+ end
32
+
25
33
  def compile(environment = nil)
34
+ return unless @project
26
35
  @environment = environment
27
- return unless @project = parse
36
+ @result = @project.slice(:services)
28
37
  set_project_url
29
38
  merge_environment_overrides! unless @environment.nil?
30
39
  transform_env_var_values!
31
40
  append_image_tags!
32
- @result = @project.slice(:services)
33
41
  end
34
42
 
35
43
  def to_deployment_params
@@ -58,16 +66,13 @@ class Envirobly::Config
58
66
 
59
67
  def set_project_url
60
68
  @project_url = dig :project
61
- if @project_url.blank?
62
- @errors << "Missing `project: <url>` top level attribute."
63
- end
64
69
  end
65
70
 
66
71
  def transform_env_var_values!
67
- @project.fetch(:services, {}).each do |name, service|
72
+ @result[:services].each do |name, service|
68
73
  service.fetch(:env, {}).each do |key, value|
69
74
  if value.is_a?(Hash) && value.has_key?(:file)
70
- @project[:services][name][:env][key] = @commit.file_content(value.fetch(:file)).strip
75
+ @result[:services][name][:env][key] = @commit.file_content(value.fetch(:file)).strip
71
76
  end
72
77
  end
73
78
  end
@@ -79,21 +84,19 @@ class Envirobly::Config
79
84
  build_context: [ ".", :dir_exists? ]
80
85
  }
81
86
  def append_image_tags!
82
- @project.fetch(:services, {}).each do |name, service|
87
+ @result[:services].each do |name, service|
83
88
  next if NON_BUILDABLE_TYPES.include?(service[:type]) || service[:image].present?
84
89
  checksums = []
85
90
 
86
91
  BUILD_DEFAULTS.each do |attribute, options|
87
92
  value = service.fetch(attribute, options.first)
88
- unless @commit.public_send(options.second, value)
89
- @errors << "Service `#{name}` specifies `#{attribute}` as `#{value}` which doesn't exist in this commit."
90
- else
93
+ if @commit.public_send(options.second, value)
91
94
  checksums << @commit.objects_with_checksum_at(value)
92
95
  end
93
96
  end
94
97
 
95
98
  if checksums.size == 2
96
- @project[:services][name][:image_tag] = Digest::SHA1.hexdigest checksums.to_json
99
+ @result[:services][name][:image_tag] = Digest::SHA1.hexdigest checksums.to_json
97
100
  end
98
101
  end
99
102
  end
@@ -102,13 +105,106 @@ class Envirobly::Config
102
105
  return unless services = @project.dig(:environments, @environment.to_sym)
103
106
  services.each do |name, service|
104
107
  service.each do |attribute, value|
105
- if value.is_a?(Hash) && @project[:services][name][attribute].is_a?(Hash)
106
- @project[:services][name][attribute].merge! value
107
- @project[:services][name][attribute].compact!
108
+ if value.is_a?(Hash) && @result[:services][name][attribute].is_a?(Hash)
109
+ @result[:services][name][attribute].merge! value
110
+ @result[:services][name][attribute].compact!
108
111
  else
109
- @project[:services][name][attribute] = value
112
+ @result[:services][name][attribute] = value
110
113
  end
111
114
  end
112
115
  end
113
116
  end
117
+
118
+ VALID_TOP_LEVEL_KEYS = %i[ project services environments ]
119
+ def validate_top_level_keys
120
+ unless @project.is_a?(Hash)
121
+ @errors << "Config doesn't contain a top level hash structure."
122
+ return
123
+ end
124
+
125
+ @errors << "Missing `project: <url>` top level attribute." if @project[:project].blank?
126
+
127
+ @project.keys.each do |key|
128
+ unless VALID_TOP_LEVEL_KEYS.include?(key)
129
+ @errors << "Top level key `#{key}` is not allowed. Allowed keys: #{VALID_TOP_LEVEL_KEYS.map{ "`#{_1}`" }.join(", ")}."
130
+ end
131
+ end
132
+ end
133
+
134
+ VALID_SERVICE_KEYS = %i[
135
+ type
136
+ image
137
+ engine_version
138
+ instance_type
139
+ min_instances
140
+ max_instances
141
+ volume_size
142
+ volume_mount
143
+ dockerfile
144
+ build_context
145
+ command
146
+ release_command
147
+ env
148
+ health_check
149
+ private
150
+ aliases
151
+ ]
152
+ NAME_FORMAT = /\A[a-z0-9\-_]+\z/
153
+ def validate_services(services)
154
+ unless services.is_a?(Hash)
155
+ @errors << "`services` key must be a hash."
156
+ return
157
+ end
158
+
159
+ services.each do |name, service|
160
+ unless name =~ NAME_FORMAT
161
+ @errors << "`#{name}` is not a valid service name. Allowed characters: a-z, 0-9, -, _"
162
+ end
163
+
164
+ unless service.is_a?(Hash)
165
+ @errors << "Service `#{name}` must be a hash."
166
+ next
167
+ end
168
+
169
+ service.each do |attribute, value|
170
+ unless VALID_SERVICE_KEYS.include?(attribute)
171
+ @errors << "Service `#{name}` attribute `#{attribute}` is not a valid attribute."
172
+ end
173
+ end
174
+
175
+ BUILD_DEFAULTS.each do |attribute, options|
176
+ value = service.fetch(attribute, options.first)
177
+ unless @commit.public_send(options.second, value)
178
+ @errors << "Service `#{name}` specifies `#{attribute}` as `#{value}` which doesn't exist in this commit."
179
+ end
180
+ end
181
+
182
+ service.fetch(:env, {}).each do |key, value|
183
+ if value.is_a?(Hash) && value.has_key?(:file)
184
+ unless @commit.file_exists?(value.fetch(:file))
185
+ @errors << "Environment variable `#{key}` referring to a file `#{value.fetch(:file)}` doesn't exist in this commit."
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+ def validate_environments
193
+ return unless @project.has_key?(:environments)
194
+
195
+ environments = @project.fetch :environments, nil
196
+
197
+ unless environments.is_a?(Hash)
198
+ @errors << "`environments` key must be a hash."
199
+ return
200
+ end
201
+
202
+ environments.each do |environment, services|
203
+ unless environment =~ NAME_FORMAT
204
+ @errors << "`#{environment}` is not a valid environment name. Allowed characters: a-z, 0-9, -, _"
205
+ end
206
+
207
+ validate_services services
208
+ end
209
+ end
114
210
  end
@@ -8,7 +8,7 @@ class Envirobly::Deployment
8
8
  end
9
9
 
10
10
  config = Envirobly::Config.new(commit)
11
- config.compile(environment)
11
+ config.validate
12
12
 
13
13
  if config.errors.any?
14
14
  $stderr.puts "Errors found while parsing #{Envirobly::Config::PATH}:"
@@ -21,6 +21,7 @@ class Envirobly::Deployment
21
21
  exit 1
22
22
  end
23
23
 
24
+ config.compile(environment)
24
25
  params = config.to_deployment_params
25
26
 
26
27
  puts "Deployment config:"
@@ -0,0 +1,17 @@
1
+ class Envirobly::Git::Unstaged < Envirobly::Git::Commit
2
+ def initialize(working_dir: Dir.getwd)
3
+ @working_dir = working_dir
4
+ end
5
+
6
+ def file_exists?(path)
7
+ File.exist? path
8
+ end
9
+
10
+ def dir_exists?(path)
11
+ Dir.exist? path
12
+ end
13
+
14
+ def file_content(path)
15
+ File.read path
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module Envirobly
2
- VERSION = "0.5.2"
2
+ VERSION = "0.6.1"
3
3
  end
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.5.2
4
+ version: 0.6.1
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-20 00:00:00.000000000 Z
11
+ date: 2024-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -130,6 +130,7 @@ files:
130
130
  - lib/envirobly/deployment.rb
131
131
  - lib/envirobly/git.rb
132
132
  - lib/envirobly/git/commit.rb
133
+ - lib/envirobly/git/unstaged.rb
133
134
  - lib/envirobly/version.rb
134
135
  homepage: https://github.com/envirobly/envirobly-cli
135
136
  licenses: