aggkit 0.3.1.8768 → 0.3.4

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.
data/lib/aggkit/ci.rb CHANGED
@@ -9,75 +9,76 @@ module Aggkit
9
9
 
10
10
  module Ci
11
11
 
12
- def log_action action
12
+ def log_action(action)
13
13
  puts " => #{action}"
14
14
  end
15
15
 
16
- def info message
16
+ def info(message)
17
17
  puts " => #{message}"
18
18
  end
19
19
 
20
- def execute cmd
20
+ def execute(cmd)
21
21
  puts " - executing: #{cmd}"
22
22
  result = `#{cmd}`
23
23
  puts result
24
- if !$?.success?
25
- raise "Execution failed cmd: #{cmd.inspect}"
26
- end
24
+ raise "Execution failed cmd: #{cmd.inspect}" unless $?.success?
25
+
27
26
  result
28
27
  end
29
28
 
30
- #Уровни образов
29
+ # Уровни образов
31
30
  # 1. Без модификатора - не протестирован, отсутсвует в репозитории.
32
31
  # 2. С модификатором dev - протестирован автотестами, ДОЛЖЕН быть в репозитории.
33
32
  # 3. С модификатором stage - протестирован руками, ДОЛЖЕН быть в репозитории(как и его предшественник dev).
34
33
  # 4. С модификатором release - помечен для релиза, ДОЛЖЕН быть в репозитории(как и его предшественник dev и stage).
35
34
 
36
- #Работа должна вестить ТОЛЬКО с workimage
35
+ # Работа должна вестить ТОЛЬКО с workimage
37
36
 
38
37
  # Базовое имя образа
39
38
  # Например docker.rnds.pro/aggredator-mq
40
- def baseimage service
39
+ def baseimage(service)
41
40
  raise "Service name invalid: #{service.inspect}" if service.to_s.length < 2
41
+
42
42
  "docker.rnds.pro/aggredator-#{service}"
43
43
  end
44
44
 
45
-
46
45
  # Текущее имя образа без модификаторов продвижения, но с тегом
47
46
  # Например docker.rnds.pro/aggredator-mq:7e6420b5
48
- def workimage service, tag
47
+ def workimage(service, tag)
49
48
  raise "Service tag invalid: #{tag.inspect}" if tag.to_s.length < 2
49
+
50
50
  "#{baseimage(service)}:#{tag}"
51
51
  end
52
52
 
53
53
  # Образ с модификатором версии
54
54
  # Например docker.rnds.pro/aggredator-mq-dev:7e6420b5
55
- def promotedimage service, stage, tag
55
+ def promotedimage(service, stage, tag)
56
56
  raise "Service stage invalid: #{stage.inspect}" if stage.to_s.length < 2
57
57
  raise "Service tag invalid: #{tag.inspect}" if tag.to_s.length < 2
58
+
58
59
  "#{baseimage(service)}-#{stage}:#{tag}"
59
60
  end
60
61
 
61
62
  # Образ с модификатором протестированной автотестами версии
62
63
  # Например docker.rnds.pro/aggredator-mq-dev:7e6420b5
63
- def devimage service, tag
64
+ def devimage(service, tag)
64
65
  promotedimage(service, 'dev', tag)
65
66
  end
66
67
 
67
68
  # Образ с модификатором стабильной версии
68
69
  # Например docker.rnds.pro/aggredator-mq-stage:7e6420b5
69
- def stageimage service, tag
70
+ def stageimage(service, tag)
70
71
  promotedimage(service, 'stage', tag)
71
72
  end
72
73
 
73
74
  # Образ с модификатором релизной версии
74
- #Например docker.rnds.pro/aggredator-mq-release:7e6420b5
75
- def releaseimage service, tag
75
+ # Например docker.rnds.pro/aggredator-mq-release:7e6420b5
76
+ def releaseimage(service, tag)
76
77
  promotedimage(service, 'release', tag)
77
78
  end
78
79
 
79
- # Протегировать образ тегом
80
- def tagimage! image, newimage, push: false, ignoreerror: false
80
+ # Протегировать образ тегом
81
+ def tagimage!(image, newimage, push: false, ignoreerror: false)
81
82
  log_action "Tag #{image.inspect} as #{newimage.inspect}"
82
83
 
83
84
  if ignoreerror
@@ -86,28 +87,26 @@ module Aggkit
86
87
  execute("docker tag #{image} #{newimage}")
87
88
  end
88
89
 
89
- if push
90
- execute("docker push #{newimage}")
91
- end
90
+ execute("docker push #{newimage}") if push
92
91
 
93
- return newimage
92
+ newimage
94
93
  end
95
94
 
96
- #Удалить образ образ тегом
97
- def rmimage! image
95
+ # Удалить образ образ тегом
96
+ def rmimage!(image)
98
97
  log_action "Remove #{image.inspect}"
99
98
  execute("docker rmi #{image} &> /dev/null || true")
100
99
  end
101
100
 
102
- def label! image, label, value
101
+ def label!(image, label, value)
103
102
  raise "Image label invalid: #{label.inspect}" if label.to_s.length < 2
104
103
  raise "Image label value invalid: #{value.inspect}" if value.to_s.length < 2
105
104
 
106
- execute("echo #{image} | docker build -t #{image} --label=\"#{label.to_s}=#{value.to_s}\" - ")
105
+ execute("echo #{image} | docker build -t #{image} --label=\"#{label}=#{value}\" - ")
107
106
  end
108
107
 
109
108
  # Растегировать все модификатора образа сервиса и возможно удалить его
110
- def untagservice service, tag
109
+ def untagservice(service, tag)
111
110
  if tag != 'latest'
112
111
  rmimage! workimage(service, tag)
113
112
  rmimage! devimage(service, tag)
@@ -117,7 +116,7 @@ module Aggkit
117
116
  end
118
117
 
119
118
  # Продвинуть текущий образ сервиса по уровню - добавить модификатор и залить в репозиторий
120
- def promote! service, tag, stage, fromstage: nil
119
+ def promote!(service, tag, stage, fromstage: nil)
121
120
  fromimage = if fromstage
122
121
  promotedimage(service, fromstage, tag)
123
122
  else
@@ -127,52 +126,50 @@ module Aggkit
127
126
  toimage = promotedimage(service, stage, tag)
128
127
 
129
128
  log_action "Promote #{fromimage} to #{toimage}"
130
- return tagimage! fromimage, toimage, push: true
129
+ tagimage! fromimage, toimage, push: true
131
130
  end
132
131
 
133
132
  # Продвинуть текущий образ по уровню - добавить модификатор dev(протестировано) и залить в репозиторий
134
- def promote_to_dev! service, tag
133
+ def promote_to_dev!(service, tag)
135
134
  promote!(service, tag, 'dev')
136
135
  end
137
136
 
138
137
  # Продвинуть текущий образ по уровню - добавить модификатор stage(стабильно) и залить в репозиторий
139
- def promote_to_stage! service, tag
138
+ def promote_to_stage!(service, tag)
140
139
  promoted = tagimage!(devimage(service, tag), stageimage(service, tag), push: true)
141
140
  # Тегируем этот образ как latest
142
- return tagimage!(promoted, stageimage(service, 'latest'), push: true)
141
+ tagimage!(promoted, stageimage(service, 'latest'), push: true)
143
142
  end
144
143
 
145
144
  # Продвинуть стабильный образ до указанного тега
146
- def promote_to_tag! service, tag, newtag
147
- return tagimage!(devimage(service, tag), stageimage(service, newtag), push: true)
145
+ def promote_to_tag!(service, tag, newtag)
146
+ tagimage!(devimage(service, tag), stageimage(service, newtag), push: true)
148
147
  end
149
148
 
150
149
  # Продвинуть список образов или упасть с ошибкой
151
- def promote_services_to_dev! services, tag
150
+ def promote_services_to_dev!(services, tag)
152
151
  [services].flatten.each do |service|
153
152
  promote_to_dev!(service, tag)
154
153
  end
155
154
  end
156
155
 
157
156
  # Продвинуть список образов или упасть с ошибкой
158
- def promote_services_to_stage! services, tag
157
+ def promote_services_to_stage!(services, tag)
159
158
  [services].flatten.each do |service|
160
159
  promote_to_stage!(service, tag)
161
160
  end
162
161
  end
163
162
 
164
- #Протегировать образы до указанного тега
165
- def promote_services_to_tag! services, tag, newtag
163
+ # Протегировать образы до указанного тега
164
+ def promote_services_to_tag!(services, tag, newtag)
166
165
  [services].flatten.each do |service|
167
166
  promote_to_tag!(service, tag, newtag)
168
167
  end
169
168
  end
170
169
 
171
-
172
-
173
170
  # Попытаться взять все модификаторы образов из репозитория
174
171
  # Скачивает образы и тегирует их как workimage
175
- def pull_images_cache services, tag
172
+ def pull_images_cache(services, tag)
176
173
  log_action "Puling images#{[services].flatten.inspect} from cache...."
177
174
  [services].flatten.each do |service|
178
175
  execute("docker pull #{workimage(service, tag)} 2> /dev/null || true")
@@ -186,15 +183,15 @@ module Aggkit
186
183
  end
187
184
 
188
185
  # Залить образы в репозиторий
189
- def push_images_cache services, tag
186
+ def push_images_cache(services, tag)
190
187
  log_action "Pushing images#{[services].flatten.inspect} to cache...."
191
188
  [services].flatten.each do |service|
192
189
  tagimage! workimage(service, tag), workimage(service, tag), push: true
193
190
  end
194
191
  end
195
192
 
196
- #Растегировать все образы для дальнейшего удаления. Помечает как latest для поддержки кеширования docker
197
- def clean_services services, tag
193
+ # Растегировать все образы для дальнейшего удаления. Помечает как latest для поддержки кеширования docker
194
+ def clean_services(services, tag)
198
195
  [services].flatten.each do |service|
199
196
  tagimage! workimage(service, tag), workimage(service, 'latest'), ignoreerror: true
200
197
  tagimage! devimage(service, tag), workimage(service, 'latest'), ignoreerror: true
@@ -204,17 +201,17 @@ module Aggkit
204
201
  end
205
202
  end
206
203
 
207
- def ssh_deploy services, env, sshserver, tag, stage
208
- with_remote_docker services, env, sshserver, tag, stage do |config, environment|
204
+ def ssh_deploy(services, env, sshserver, tag, stage)
205
+ with_remote_docker services, env, sshserver, tag, stage do |config, _environment|
209
206
  config_file = config['config_file'].to_s
210
207
 
211
208
  execute('docker-compose ps')
212
209
  execute('docker-compose pull')
213
210
 
214
- consul = execute('docker ps | grep consul').split(' ').first.strip
211
+ consul = execute('docker-compose ps | grep consul').split(' ').first.strip
215
212
  puts "CONSULT ID: #{consul}"
216
213
 
217
- if !config_file.empty?
214
+ unless config_file.empty?
218
215
  execute("docker exec -i #{consul} aggwait -t 20 --consul")
219
216
  execute("docker exec -i #{consul} aggconsul --init --override --config - < #{config_file}")
220
217
  end
@@ -223,38 +220,38 @@ module Aggkit
223
220
  end
224
221
  end
225
222
 
226
- def ssh_core_deploy services, env, sshserver, tag, stage
227
- with_remote_docker services, env, sshserver, tag, stage do |config, environment|
223
+ def ssh_core_deploy(services, env, sshserver, tag, stage)
224
+ with_remote_docker services, env, sshserver, tag, stage do |config, _environment|
228
225
  config_file = config['config_file'].to_s
229
226
 
230
227
  execute('docker-compose ps')
231
228
  execute('docker-compose pull')
232
229
  execute('docker-compose up -t 30 -d consul')
233
230
 
234
- consul = execute('docker ps | grep consul').split(' ').first.strip
231
+ consul = execute('docker-compose ps | grep consul').split(' ').first.strip
235
232
  puts "CONSULT ID: #{consul}"
236
233
 
237
- if !config_file.empty?
234
+ unless config_file.empty?
238
235
  execute("docker exec -i #{consul} aggwait -t 20 --consul")
239
236
  execute("docker exec -i #{consul} aggconsul --init --override --config - < #{config_file}")
240
237
  end
241
238
 
242
- #echo " * Consul ready"
243
- #echo " * Updatting database..."
239
+ # echo " * Consul ready"
240
+ # echo " * Updatting database..."
244
241
  execute('docker-compose up -t 30 -d db')
245
242
  sleep 5
246
- #echo " * Db ready"
247
- #echo " * Bootstrapping admin..."
243
+ # echo " * Db ready"
244
+ # echo " * Bootstrapping admin..."
248
245
  execute('docker-compose run --rm -T admin /home/app/docker/bootstrap.rb')
249
246
  sleep 5
250
- #echo " * Bootstrapping complete"
251
- #echo " * Updating all containers..."
247
+ # echo " * Bootstrapping complete"
248
+ # echo " * Updating all containers..."
252
249
  execute('docker-compose up -t 30 -d')
253
- #echo " * Containers ready"
250
+ # echo " * Containers ready"
254
251
  end
255
252
  end
256
253
 
257
- def with_remote_docker services, env, sshserver, tag, stage
254
+ def with_remote_docker(services, env, sshserver, tag, stage)
258
255
  services = [services].flatten
259
256
  log_action "Deploy [#{services.inspect}] tag:#{tag.inspect} stage:#{stage.inspect} to #{sshserver.inspect}"
260
257
  with_ssh sshserver do |sockname|
@@ -265,14 +262,12 @@ module Aggkit
265
262
  envs['CORE_TAG'] = tag
266
263
  envs['CORE_SUFFIX'] = "-#{stage}"
267
264
 
268
- localid = execute("docker info | grep ID").strip
265
+ localid = execute('docker info | grep ID').strip
269
266
 
270
267
  Aggkit::Env.with_env(envs) do |environment|
271
- remoteid = execute("docker info | grep ID").strip
268
+ remoteid = execute('docker info | grep ID').strip
272
269
 
273
- if localid == remoteid
274
- raise "Can't get access to remote Docker"
275
- end
270
+ raise "Can't get access to remote Docker" if localid == remoteid
276
271
 
277
272
  yield(env_config, environment)
278
273
 
@@ -282,12 +277,11 @@ module Aggkit
282
277
  tagimage! deployed, current
283
278
  untagservice(service, tag)
284
279
  end
285
-
286
280
  end
287
281
  end
288
282
  end
289
283
 
290
- def with_ssh server, user: 'root', &block
284
+ def with_ssh(server, user: 'root')
291
285
  file = Tempfile.new
292
286
  @ssh_sockname = file.path
293
287
  file.unlink
@@ -304,3 +298,4 @@ module Aggkit
304
298
  end
305
299
 
306
300
  end
301
+
data/lib/aggkit/env.rb CHANGED
@@ -4,6 +4,7 @@ require 'English'
4
4
  require 'dotenv'
5
5
 
6
6
  module Dotenv
7
+
7
8
  module_function
8
9
 
9
10
  def load_without_export(*filenames)
@@ -13,19 +14,21 @@ module Dotenv
13
14
  end
14
15
  end
15
16
  end
17
+
16
18
  end
17
19
 
18
20
  module Aggkit
19
21
 
20
22
  class Env
23
+
21
24
  attr_accessor :project, :name, :env_root, :environment
22
25
 
23
- def self.list path = Dir.pwd
26
+ def self.list(path = Dir.pwd)
24
27
  root = Project.new(path).project_root
25
28
  Pathfinder.new(root).each_env
26
29
  end
27
30
 
28
- def self.with_env env, &block
31
+ def self.with_env(env)
29
32
  current_env = ENV.to_h
30
33
  env.each_pair do |k, v|
31
34
  ENV[k.to_s] = v.to_s
@@ -41,7 +44,7 @@ module Aggkit
41
44
  end
42
45
  end
43
46
 
44
- def initialize path
47
+ def initialize(path)
45
48
  @project = if File.directory?(File.expand_path(path))
46
49
  @name = File.basename(File.realpath(File.expand_path(path)))
47
50
  Project.new(path)
@@ -50,19 +53,19 @@ module Aggkit
50
53
  Project.new(Dir.pwd)
51
54
  end
52
55
 
53
- if !self.class.list.include?(@name)
56
+ unless self.class.list.include?(@name)
54
57
  raise "There no env #{@name.inspect} in project: #{project.project_root.inspect}"
55
58
  end
56
59
 
57
60
  @env_root = File.join(project_root, 'envs', @name)
58
61
  end
59
62
 
60
- def prepare release: false
63
+ def prepare(release: false)
61
64
  @environment = prepare_environment(release: release)
62
65
  end
63
66
 
64
- def with_env &block
65
- Env.with_env(environment) &block
67
+ def with_env(&block)
68
+ Env.with_env(environment) & block
66
69
  end
67
70
 
68
71
  def project_root
@@ -82,148 +85,161 @@ module Aggkit
82
85
  end
83
86
 
84
87
  def core_dot_file
85
- File.join(core_root, '.env') rescue nil
88
+ begin
89
+ File.join(core_root, '.env')
90
+ rescue StandardError
91
+ nil
92
+ end
86
93
  end
87
94
 
88
95
  def env_files
89
- [core_dot_file, project_dot_file, dot_file].compact.select{|f| File.exists?(f)}.uniq
96
+ [core_dot_file, project_dot_file, dot_file].compact.select{|f| File.exist?(f) }.uniq
90
97
  end
91
98
 
92
99
  def config_file
93
- [File.join(env_root, 'config.yml'), File.join(env_root, 'config.yaml')].compact.select{|f| File.exists?(f)}.uniq.first
100
+ [File.join(env_root, 'config.yml'), File.join(env_root, 'config.yaml')].compact.select{|f| File.exist?(f) }.uniq.first
94
101
  end
95
102
 
96
103
  def show
97
104
  {
98
- name: name,
105
+ name: name,
99
106
  project_root: project_root,
100
- core_root: core_root,
101
- envfiles: env_files,
102
- config_file: config_file,
103
- envs: environment,
107
+ core_root: core_root,
108
+ envfiles: env_files,
109
+ config_file: config_file,
110
+ envs: environment
104
111
  }
105
112
  end
106
113
 
107
- private
108
-
114
+ private
109
115
 
110
- def prepare_environment release: false
111
- base_env = {
112
- 'ENV_ROOT' => env_root,
113
- 'PROJECT_ROOT' => project_root,
114
- 'CORE_ROOT' => core_root,
115
- 'PATH' => check_path_variable(env_root),
116
- }
117
116
 
118
- dot_env = prepare_dot(base_env)
117
+ def prepare_environment(release: false)
118
+ base_env = {
119
+ 'ENV_ROOT' => env_root,
120
+ 'PROJECT_ROOT' => project_root,
121
+ 'CORE_ROOT' => core_root,
122
+ 'PATH' => check_path_variable(env_root)
123
+ }
119
124
 
120
- compose_env = prepare_compose(dot_env.merge(base_env), release: release)
125
+ dot_env = prepare_dot(base_env)
121
126
 
122
- dot_env.merge(base_env).merge(compose_env)
123
- end
127
+ compose_env = prepare_compose(dot_env.merge(base_env), release: release)
124
128
 
125
- def prepare_dot env
126
- Env.with_env(env) do
127
- Dotenv.load_without_export(*env_files)
129
+ dot_env.merge(base_env).merge(compose_env)
128
130
  end
129
- end
130
131
 
131
- def prepare_compose env, release: false
132
- compose_files = if env['COMPOSE_FILE']
133
- env['COMPOSE_FILE']
134
- elsif File.exists?(File.join(env_root, "docker-compose.yml"))
135
- File.join(env_root, "docker-compose.yml")
136
- elsif File.exists?(File.join(env_root, "docker-compose.yaml"))
137
- File.join(env_root, "docker-compose.yaml")
132
+ def prepare_dot(env)
133
+ Env.with_env(env) do
134
+ Dotenv.load_without_export(*env_files)
135
+ end
138
136
  end
139
137
 
140
- if compose_files
141
- result_file = File.join(env_root, "compose-result.yml")
142
- Env.with_env(env.merge('COMPOSE_FILE' => compose_files)) do
143
- if release
144
- `aggmerge #{result_file} --skip-build`
145
- else
146
- `aggmerge #{result_file}`
138
+ def prepare_compose(env, release: false)
139
+ compose_files = if env['COMPOSE_FILE']
140
+ env['COMPOSE_FILE']
141
+ elsif File.exist?(File.join(env_root, 'docker-compose.yml'))
142
+ File.join(env_root, 'docker-compose.yml')
143
+ elsif File.exist?(File.join(env_root, 'docker-compose.yaml'))
144
+ File.join(env_root, 'docker-compose.yaml')
145
+ end
146
+
147
+ if compose_files
148
+ result_file = File.join(env_root, 'compose-result.yml')
149
+ Env.with_env(env.merge('COMPOSE_FILE' => compose_files)) do
150
+ if release
151
+ `aggmerge #{result_file} --skip-build`
152
+ else
153
+ `aggmerge #{result_file}`
154
+ end
147
155
  end
156
+ {
157
+ 'COMPOSE_FILE' => result_file
158
+ }
159
+ else
160
+ {}
148
161
  end
149
- {
150
- 'COMPOSE_FILE' => result_file
151
- }
152
- else
153
- {}
154
162
  end
155
- end
156
163
 
157
- def check_path_variable path
158
- if ENV['PATH'][path]
159
- ENV['PATH']
160
- else
161
- "#{ENV['PATH']}:#{path}"
164
+ def check_path_variable(path)
165
+ if ENV['PATH'][path]
166
+ ENV['PATH']
167
+ else
168
+ "#{ENV['PATH']}:#{path}"
169
+ end
162
170
  end
163
- end
164
171
 
165
- class Pathfinder
166
- attr_accessor :path
172
+ class Pathfinder
167
173
 
168
- def initialize path
169
- @path = File.realpath(File.expand_path(path))
170
- end
171
174
 
172
- def each_parent
173
- current = path.split(File::SEPARATOR)
174
- Enumerator.new do |y|
175
- while !current.empty? do
176
- y << current.join(File::SEPARATOR)
177
- current.pop
175
+ attr_accessor :path
176
+
177
+ def initialize(path)
178
+ @path = File.realpath(File.expand_path(path))
179
+ end
180
+
181
+ def each_parent
182
+ current = path.split(File::SEPARATOR)
183
+ Enumerator.new do |y|
184
+ until current.empty?
185
+ y << current.join(File::SEPARATOR)
186
+ current.pop
187
+ end
178
188
  end
179
189
  end
180
- end
181
190
 
182
- def each_env
183
- Dir.chdir(File.join(path, 'envs')) do
184
- Dir.glob('**/*').select do |f|
185
- File.directory? f
186
- end.select do |f|
187
- File.exists?(File.join(f, '.env')) || File.exists?(File.join(f, 'docker-compose.yml')) || File.exists?(File.join(f, 'docker-compose.yaml'))
188
- end.sort
191
+ def each_env
192
+ Dir.chdir(File.join(path, 'envs')) do
193
+ Dir.glob('**/*').select do |f|
194
+ File.directory? f
195
+ end.select do |f|
196
+ File.exist?(File.join(f, '.env')) || File.exist?(File.join(f, 'docker-compose.yml')) || File.exist?(File.join(f, 'docker-compose.yaml'))
197
+ end.sort
198
+ end
189
199
  end
190
- end
191
- end
192
200
 
193
- class Project
194
- attr_accessor :env_root
195
201
 
196
- def initialize path
197
- raise "env path #{path} is not directory!" if !File.directory?(File.expand_path(path))
198
- @env_root = File.realpath(File.expand_path(path))
199
202
  end
200
203
 
201
- def project_root
202
- @project_root = Pathfinder.new(env_root).each_parent.find do |path|
203
- root?(path)
204
- end || (raise "Can't find project root")
205
- end
204
+ class Project
205
+
206
206
 
207
- def core_root
208
- @core_root = Pathfinder.new(project_root).each_parent.find do |path|
209
- core?(path)
207
+ attr_accessor :env_root
208
+
209
+ def initialize(path)
210
+ raise "env path #{path} is not directory!" unless File.directory?(File.expand_path(path))
211
+
212
+ @env_root = File.realpath(File.expand_path(path))
210
213
  end
211
- end
212
214
 
213
- def root? path
214
- return File.realpath(File.expand_path(path)) if File.directory?("#{path}/.git") ||
215
- File.exists?("#{path}/base-service.yml") ||
216
- File.exists?("#{path}/common-services.yml") ||
217
- File.directory?("#{path}/envs")
218
- end
215
+ def project_root
216
+ @project_root = Pathfinder.new(env_root).each_parent.find do |path|
217
+ root?(path)
218
+ end || (raise "Can't find project root")
219
+ end
219
220
 
220
- def core? path
221
- return File.realpath(File.expand_path(path)) if File.exists?("#{path}/.core")
222
- end
221
+ def core_root
222
+ @core_root = Pathfinder.new(project_root).each_parent.find do |path|
223
+ core?(path)
224
+ end
225
+ end
223
226
 
224
- end
227
+ def root?(path)
228
+ return File.realpath(File.expand_path(path)) if File.directory?("#{path}/.git") ||
229
+ File.exist?("#{path}/base-service.yml") ||
230
+ File.exist?("#{path}/common-services.yml") ||
231
+ File.directory?("#{path}/envs")
232
+ end
233
+
234
+ def core?(path)
235
+ return File.realpath(File.expand_path(path)) if File.exist?("#{path}/.core")
236
+ end
237
+
238
+
239
+ end
225
240
 
226
241
 
227
242
  end
228
243
 
229
244
  end
245
+