satorix 0.0.1 → 1.5.3
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 +5 -5
- data/.gitignore +4 -1
- data/.gitlab-ci.yml +45 -0
- data/.rspec +2 -1
- data/.rubocop.yml +11 -0
- data/.ruby-version +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +25 -0
- data/Procfile +1 -0
- data/README.md +93 -1
- data/Rakefile +8 -4
- data/bin/console +3 -3
- data/bin/satorix +8 -0
- data/lib/satorix/CI/deploy/flynn/environment_variables.rb +123 -0
- data/lib/satorix/CI/deploy/flynn/resources.rb +79 -0
- data/lib/satorix/CI/deploy/flynn/routes.rb +267 -0
- data/lib/satorix/CI/deploy/flynn/scale.rb +52 -0
- data/lib/satorix/CI/deploy/flynn.rb +132 -0
- data/lib/satorix/CI/shared/buildpack_manager/buildpack.rb +159 -0
- data/lib/satorix/CI/shared/buildpack_manager.rb +220 -0
- data/lib/satorix/CI/shared/ruby/gem_manager.rb +80 -0
- data/lib/satorix/CI/shared/yarn_manager.rb +25 -0
- data/lib/satorix/CI/test/python/django_test.rb +38 -0
- data/lib/satorix/CI/test/python/safety.rb +30 -0
- data/lib/satorix/CI/test/ruby/brakeman.rb +35 -0
- data/lib/satorix/CI/test/ruby/bundler_audit.rb +35 -0
- data/lib/satorix/CI/test/ruby/cucumber.rb +29 -0
- data/lib/satorix/CI/test/ruby/rails_test.rb +29 -0
- data/lib/satorix/CI/test/ruby/rspec.rb +29 -0
- data/lib/satorix/CI/test/ruby/rubocop.rb +98 -0
- data/lib/satorix/CI/test/shared/database.rb +74 -0
- data/lib/satorix/shared/console.rb +157 -0
- data/lib/satorix/version.rb +1 -1
- data/lib/satorix.rb +343 -2
- data/satorix/CI/deploy/ie_gem_server.rb +80 -0
- data/satorix/CI/deploy/rubygems.rb +81 -0
- data/satorix/custom.rb +21 -0
- data/satorix.gemspec +13 -11
- metadata +57 -29
- data/.travis.yml +0 -5
@@ -0,0 +1,267 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Deploy
|
4
|
+
module Flynn
|
5
|
+
module Routes
|
6
|
+
|
7
|
+
|
8
|
+
def find_or_create_route(domain)
|
9
|
+
route_ids = route_ids(domain)
|
10
|
+
if route_ids.empty?
|
11
|
+
log "Adding route for #{ domain }..."
|
12
|
+
route_ids << fc_route_add(domain)
|
13
|
+
log "Route for #{ domain } added with the ID of #{ route_ids.first }."
|
14
|
+
else
|
15
|
+
multiple = route_ids.length > 1
|
16
|
+
log "Route#{ 's' if multiple } already exist#{ 's' unless multiple } for #{ domain }."
|
17
|
+
end
|
18
|
+
|
19
|
+
route_ids
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def configure_routes
|
24
|
+
defined_and_internal_routes.each do |ddev_id, domain|
|
25
|
+
route_ids = find_or_create_route(domain)
|
26
|
+
route_ids.each do |route_id|
|
27
|
+
add_tls_to_route(route_id: route_id, ddev_id: ddev_id)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def add_tls_to_route(route_id:, ddev_id:)
|
34
|
+
domain = defined_and_internal_routes[ddev_id]
|
35
|
+
if use_tls?(ddev_id)
|
36
|
+
if use_lets_encrypt?(ddev_id)
|
37
|
+
log "Using Let's Encrypt for #{ domain }."
|
38
|
+
log_error_and_abort "Let's Encrypt support is not implemented, yet!"
|
39
|
+
else
|
40
|
+
log "Using #{ user_defined_tls?(ddev_id) ? 'custom' : 'default' } certificate details for #{ domain } (#{ service_for_route_id(route_id) } service)."
|
41
|
+
File.open('crt', 'w') { |f| f.write(crt_for_ddev_id(ddev_id)) }
|
42
|
+
File.open('key', 'w') { |f| f.write(key_for_ddev_id(ddev_id)) }
|
43
|
+
fc_route_update(route_id)
|
44
|
+
end
|
45
|
+
else
|
46
|
+
log "Skipping TLS configuration for #{ domain }."
|
47
|
+
log "Environment variables #{ env_var_crt_prefix }#{ ddev_id } and #{ env_var_key_prefix }#{ ddev_id } have not been specified."
|
48
|
+
log 'For more information, please refer to https://www.satorix.com/docs/user/projects#certificates'
|
49
|
+
end
|
50
|
+
log ''
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def canonical_domain
|
55
|
+
ENV["AEEV_#{ current_branch }_SATORIX_CANONICAL_URI_HOST"]
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def canonical_domain_information
|
60
|
+
"\nThe above routes will all be redirected to the default URL:\n\n\t#{ canonical_uri }\n\n" if canonical_uri?
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def canonical_domain_protocol
|
65
|
+
ENV["AEEV_#{ current_branch }_SATORIX_CANONICAL_URI_PROTOCOL"]
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def canonical_uri
|
70
|
+
"#{ canonical_domain_protocol }://#{ canonical_domain }" if canonical_uri?
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def canonical_uri?
|
75
|
+
[canonical_domain, canonical_domain_protocol].all? { |x| x.to_s !~ only_whitespace }
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def crt_for_ddev_id(ddev_id)
|
80
|
+
ENV["#{ env_var_crt_prefix }#{ user_defined_tls?(ddev_id) ? ddev_id : 'DEFAULT' }"]
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def custom_crt_for_ddev_id?(ddev_id)
|
85
|
+
ENV["#{ env_var_crt_prefix }#{ ddev_id }"].to_s !~ only_whitespace
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def custom_key_for_ddev_id?(ddev_id)
|
90
|
+
ENV["#{ env_var_key_prefix }#{ ddev_id }"].to_s !~ only_whitespace
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
def defined_and_internal_routes
|
95
|
+
defined_routes.merge flynn_internal_routes
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
def defined_routes
|
100
|
+
{}.tap do |routes|
|
101
|
+
invalid_keys = flynn_internal_routes.keys
|
102
|
+
ENV.each do |key, value|
|
103
|
+
next unless key.start_with?(env_var_domain_prefix)
|
104
|
+
renamed_key = key.sub(env_var_domain_prefix, '')
|
105
|
+
message = "The user-defined route #{ key } conflicts with an internal route."
|
106
|
+
log_error_and_abort message if invalid_keys.include?(renamed_key)
|
107
|
+
routes[renamed_key] = value
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
def display_routing_information
|
114
|
+
log 'All application routes...'
|
115
|
+
log ''
|
116
|
+
log urlified_routes_for_display.map { |r| "\t#{ r }" }
|
117
|
+
log canonical_domain_information if canonical_uri?
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
def env_var_crt_prefix
|
122
|
+
"CRT_#{ current_branch }_"
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
def env_var_domain_prefix
|
127
|
+
"DDEV_#{ current_branch }_"
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
def env_var_key_prefix
|
132
|
+
"KEY_#{ current_branch }_"
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
def fc_route
|
137
|
+
run_command("flynn -a #{ project_name } route", quiet: true).chomp
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
def fc_route_add(domain)
|
142
|
+
run_command("flynn route add http #{ domain } --sticky").chomp
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
def fc_route_remove(route_id)
|
147
|
+
run_command "flynn route remove #{ route_id }"
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
def fc_route_update(route_id)
|
152
|
+
run_command "flynn route update #{ route_id } --tls-cert=crt --tls-key=key --sticky", quiet: true
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
def flynn_internal_routes
|
157
|
+
{ 'FLYNN_INTERNAL' => "#{ project_name }.#{ domain_for_web_host }" }
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
def key_for_ddev_id(ddev_id)
|
162
|
+
ENV["#{ env_var_key_prefix }#{ user_defined_tls?(ddev_id) ? ddev_id : 'DEFAULT' }"]
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
def only_whitespace
|
167
|
+
/\A\s*\z/m
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
def remove_undefined_routes
|
172
|
+
routes_to_remove.each do |route|
|
173
|
+
log_header "Removing undefined route #{ route[routes_legend['ROUTE']] }..."
|
174
|
+
fc_route_remove route[routes_legend['ID']]
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
def route_ids(route)
|
180
|
+
[].tap do |route_ids|
|
181
|
+
routes_all_of('ROUTE').map { |r| r.sub(/https??:/i, '') }.each_with_index do |r, i|
|
182
|
+
route_ids << routes_all_of('ID')[i] if r == route
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
def routes
|
189
|
+
routes_with_legend.drop(1)
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
def routes_all_of(field)
|
194
|
+
routes.map { |a| a[routes_legend[field]] }
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
def routes_legend
|
199
|
+
{}.tap { |h| routes_with_legend.first.each_with_index { |route, index| h[route] = index } }
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
def routes_to_remove
|
204
|
+
routes.reject do |route|
|
205
|
+
defined_and_internal_routes.values.include? route[routes_legend['ROUTE']].partition(':').last
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
def routes_with_legend
|
211
|
+
fc_route.split("\n").map(&:split)
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
def service_for_route_id(route_id)
|
216
|
+
index = routes_all_of('ID').index(route_id)
|
217
|
+
routes_all_of('SERVICE')[index]
|
218
|
+
end
|
219
|
+
|
220
|
+
|
221
|
+
def setup_routes
|
222
|
+
configure_routes
|
223
|
+
remove_undefined_routes
|
224
|
+
display_routing_information
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
def urlified_routes
|
229
|
+
routes_all_of('ROUTE').map { |r| urlify_route r }
|
230
|
+
end
|
231
|
+
|
232
|
+
|
233
|
+
def urlified_routes_for_display
|
234
|
+
urlified_routes.map { |route| urlify_route_for_display route }.sort
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
def urlify_route(route)
|
239
|
+
route.sub(':', '://')
|
240
|
+
end
|
241
|
+
|
242
|
+
|
243
|
+
def urlify_route_for_display(route)
|
244
|
+
route =~ /^http:/ ? route : "#{ route.sub 'https', 'http' }, #{ route }"
|
245
|
+
end
|
246
|
+
|
247
|
+
|
248
|
+
def use_lets_encrypt?(ddev_id)
|
249
|
+
crt_for_ddev_id(ddev_id).to_s.gsub(/\W+/, '').casecmp('letsencrypt').zero? &&
|
250
|
+
key_for_ddev_id(ddev_id).to_s.gsub(/\W+/, '').casecmp('letsencrypt').zero?
|
251
|
+
end
|
252
|
+
|
253
|
+
|
254
|
+
def use_tls?(ddev_id)
|
255
|
+
[crt_for_ddev_id(ddev_id), key_for_ddev_id(ddev_id)].all? { |x| x.to_s !~ only_whitespace }
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
def user_defined_tls?(ddev_id)
|
260
|
+
custom_crt_for_ddev_id?(ddev_id) && custom_key_for_ddev_id?(ddev_id)
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Deploy
|
4
|
+
module Flynn
|
5
|
+
module Scale
|
6
|
+
|
7
|
+
|
8
|
+
def adjust_scale
|
9
|
+
cached_scale_options_to_set = scale_options_to_set
|
10
|
+
log "No scale specified in #{ defined_scale_key }. Displaying current scale:" if cached_scale_options_to_set.empty?
|
11
|
+
fc_scale cached_scale_options_to_set
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def current_scale
|
16
|
+
scale_string_to_hash fc_scale
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def defined_scale
|
21
|
+
scale_string_to_hash ENV[defined_scale_key].to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def defined_scale_key
|
26
|
+
"FLYNN_#{ current_branch }_SCALE"
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def fc_scale(scale_options_to_set = nil)
|
31
|
+
run_command "flynn scale#{ " #{ scale_options_to_set }" unless scale_options_to_set.nil? || scale_options_to_set.empty? }".chomp
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def scale_options_to_set
|
36
|
+
[].tap do |scale|
|
37
|
+
defined_scale.each { |job, workers| scale << "#{ job }=#{ workers }" }
|
38
|
+
(current_scale.keys - defined_scale.keys).each { |job| scale << "#{ job }=0" } unless defined_scale.empty?
|
39
|
+
end.join(' ')
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def scale_string_to_hash(scale_string)
|
44
|
+
{}.tap { |jobs| scale_string.split.map { |x| x.partition('=') }.each { |x| jobs[x.first.to_sym] = x.last } }
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Deploy
|
4
|
+
module Flynn
|
5
|
+
|
6
|
+
|
7
|
+
include Satorix
|
8
|
+
include Satorix::Shared::Console
|
9
|
+
|
10
|
+
require_relative 'flynn/environment_variables'
|
11
|
+
include EnvironmentVariables
|
12
|
+
|
13
|
+
require_relative 'flynn/resources'
|
14
|
+
include Resources
|
15
|
+
|
16
|
+
require_relative 'flynn/routes'
|
17
|
+
include Routes
|
18
|
+
|
19
|
+
require_relative 'flynn/scale'
|
20
|
+
include Scale
|
21
|
+
|
22
|
+
|
23
|
+
extend self
|
24
|
+
|
25
|
+
|
26
|
+
def go
|
27
|
+
log_bench('Adding a local reference to the remote Flynn cluster...') { add_cluster }
|
28
|
+
log_bench('Creating Flynn project...') { create_project }
|
29
|
+
log_bench('Adding Flynn remote to CI local git...') { add_remote }
|
30
|
+
log_bench('Adjusting Flynn environment variables...') { adjust_env_vars }
|
31
|
+
log_bench('Configuring Flynn inactive slug release count...') { configure_inactive_slug_releases }
|
32
|
+
log_bench('Setting resources...') { set_resources }
|
33
|
+
log_bench('Deploying to Flynn...') { deploy }
|
34
|
+
log_bench('Running Database migrations...') { run_database_migrations } if run_database_migrations?
|
35
|
+
log_bench('Scaling application processes...') { adjust_scale }
|
36
|
+
log_bench('Setting up routes...') { setup_routes }
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def skip_buildpack
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def add_cluster
|
46
|
+
run_command "flynn cluster add --force --default --tls-pin=#{ tls_pin } #{ cluster_name } #{ domain_for_cluster } #{ key }", filtered_text: [tls_pin, key]
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def add_remote
|
51
|
+
run_command "flynn -a #{ project_name } remote add #{ cluster_name } -y"
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def cluster_name
|
56
|
+
domain_for_cluster
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def configure_inactive_slug_releases
|
61
|
+
run_command 'flynn meta set gc.max_inactive_slug_releases=2'
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def create_project
|
66
|
+
if project_exists?
|
67
|
+
log "Skipping - Flynn project '#{ project_name }' already exists."
|
68
|
+
else
|
69
|
+
run_command "flynn create --remote=#{ cluster_name } -y #{ project_name }"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def deploy
|
75
|
+
run_command "git push #{ cluster_name } HEAD:refs/heads/master"
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def domain_for_cluster
|
80
|
+
ENV["FLYNN_#{ current_branch }_DOMAIN"]
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def domain_for_web_host
|
85
|
+
"#{ current_branch.downcase }.#{ hosting_namespace }"
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def hosting_namespace
|
90
|
+
if ENV['SATORIX_HOSTING_NAMESPACE'].to_s !~ only_whitespace
|
91
|
+
ENV['SATORIX_HOSTING_NAMESPACE']
|
92
|
+
else
|
93
|
+
log_error_and_abort("Satorix configuration error: Missing SATORIX_HOSTING_NAMESPACE.\n\nPlease contact support.\n")
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
def key
|
100
|
+
ENV["FLYNN_#{ current_branch }_KEY"]
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
def project_exists?
|
105
|
+
`flynn apps`.split(/\R/).map { |a| a.split.last }.include? project_name
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
def run_database_migrations?
|
110
|
+
[rails_app?, django_app?].any?
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
def run_database_migrations
|
115
|
+
if desired_resource_provider_names.nil? || desired_resource_provider_names.empty?
|
116
|
+
log 'Skipping migrations, no database has been defined. Please see the resources section of this log for more information.'
|
117
|
+
else
|
118
|
+
run_command('flynn run --enable-log bundle exec rake db:migrate') if rails_app?
|
119
|
+
run_command('flynn run --enable-log python public/manage.py migrate') if django_app?
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
def tls_pin
|
125
|
+
ENV["FLYNN_#{ current_branch }_TLSPIN"]
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module Satorix
|
2
|
+
module CI
|
3
|
+
module Shared
|
4
|
+
module BuildpackManager
|
5
|
+
|
6
|
+
|
7
|
+
class Buildpack
|
8
|
+
|
9
|
+
|
10
|
+
require 'fileutils'
|
11
|
+
require 'uri'
|
12
|
+
|
13
|
+
|
14
|
+
include Satorix::Shared::Console
|
15
|
+
|
16
|
+
|
17
|
+
attr_accessor :commit_sha_short,
|
18
|
+
:url
|
19
|
+
|
20
|
+
|
21
|
+
def go
|
22
|
+
log_error_and_abort 'Buildpack.go should not be called directly - use BuildpackManager.go.'
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def initialize(initialization_url)
|
27
|
+
self.url, self.commit_sha_short = initialization_url.to_s.strip.split('#')
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def compile
|
32
|
+
log_bench "Building application using the #{ name } buildpack..." do
|
33
|
+
run_command [compile_binary_path,
|
34
|
+
Satorix.build_dir,
|
35
|
+
Satorix.paths[:cache],
|
36
|
+
Satorix.paths[:env]]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def compile_binary_path
|
42
|
+
bin_path = File.join(path, 'bin')
|
43
|
+
test_compile_path = File.join(bin_path, 'test-compile')
|
44
|
+
compile_path = File.join(bin_path, 'compile')
|
45
|
+
File.exist?(test_compile_path) ? test_compile_path : compile_path
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def detected?
|
50
|
+
if BuildpackManager.custom_buildpacks?
|
51
|
+
log "Custom Buildpack: #{ name }."
|
52
|
+
else
|
53
|
+
command = [File.join(path, 'bin', 'detect'), Satorix.build_dir]
|
54
|
+
buildpack_name = run_command(command, quiet: true).chomp
|
55
|
+
log "Detected Framework: #{ buildpack_name }."
|
56
|
+
end
|
57
|
+
true
|
58
|
+
rescue SystemExit
|
59
|
+
# By design, buildpacks return a non-zero exit code
|
60
|
+
# (which raises a SystemExit exception) when not detected.
|
61
|
+
# This is not particularly exceptional, so we just return false.
|
62
|
+
false
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def name
|
67
|
+
File.basename(URI.parse(url).path, ".git")
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def path
|
72
|
+
File.join Satorix.paths[:buildpacks], name
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
def ensure_correctness
|
77
|
+
unless correct_version?
|
78
|
+
delete!
|
79
|
+
checkout
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def delete!
|
85
|
+
FileUtils.rm_rf path
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def exist?
|
90
|
+
Dir.exist? path
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
def checkout
|
95
|
+
log "Downloading Buildpack: #{ url }."
|
96
|
+
commit_sha_short ? checkout_specific_version : checkout_newest_version
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def checkout_specific_version
|
101
|
+
run_command ['git', 'clone', '--quiet', '--no-checkout', url, path], quiet: true
|
102
|
+
Dir.chdir(path) { run_command ['git', 'checkout', '--quiet', commit_sha_short], quiet: true }
|
103
|
+
Dir.chdir(path) { run_command ['git', 'submodule', 'update', '--init', '--recursive'], quiet: true }
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
def checkout_newest_version
|
108
|
+
run_command ['git', 'clone', '--quiet', '--recursive', '--depth', '1', url, path], quiet: true
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
def correct_version?
|
113
|
+
exist? &&
|
114
|
+
commit_sha_short &&
|
115
|
+
commit_sha_short == current_commit_sha_short_on_disk
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
def commit_sha_length
|
120
|
+
commit_sha_short ? commit_sha_short.to_s.length : 7
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
def satorix_distrib_sha_version
|
125
|
+
IO.binread(satorix_distrib_sha_path).strip if satorix_distrib_sha?
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
def satorix_distrib_sha?
|
130
|
+
File.exist? satorix_distrib_sha_path
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
def satorix_distrib_sha_path
|
135
|
+
File.join(path, '.distrib-sha')
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
def git_sha_short
|
140
|
+
Dir.chdir(path) do
|
141
|
+
# Also works: `git show -s --format=%h`.strip
|
142
|
+
run_command(['git', 'rev-parse', "--short=#{ commit_sha_length }", 'HEAD'], quiet: true).strip
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
def current_commit_sha_short_on_disk
|
148
|
+
return '' unless exist?
|
149
|
+
satorix_distrib_sha_version || git_sha_short
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|