djin 0.8.0 → 0.11.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +27 -11
- data/.gitignore +1 -0
- data/.irbrc +4 -0
- data/.rubocop.yml +5 -0
- data/CHANGELOG.md +17 -0
- data/Dockerfile +10 -3
- data/Gemfile +4 -0
- data/Gemfile.lock +41 -18
- data/README.md +138 -11
- data/Vertofile +12 -19
- data/djin.gemspec +3 -1
- data/djin.yml +13 -2
- data/docker-compose.yml +16 -2
- data/docker-entrypoint.sh +7 -0
- data/examples/djin.yml +13 -7
- data/examples/djin_lib/test.yml +12 -0
- data/examples/local_tasks/.djin/server_tasks.yml +17 -0
- data/examples/local_tasks/djin.yml +22 -0
- data/examples/remote_tasks/djin.yml +9 -0
- data/lib/djin.rb +67 -17
- data/lib/djin/cli.rb +36 -0
- data/lib/djin/config_loader.rb +124 -30
- data/lib/djin/entities/include_config.rb +47 -0
- data/lib/djin/entities/include_config/base.rb +16 -0
- data/lib/djin/entities/include_config/local.rb +16 -0
- data/lib/djin/entities/{file_config.rb → main_config.rb} +16 -1
- data/lib/djin/extensions/hash_extensions.rb +14 -0
- data/lib/djin/extensions/object_extensions.rb +24 -0
- data/lib/djin/include_resolver.rb +50 -0
- data/lib/djin/interpreter.rb +11 -4
- data/lib/djin/interpreter/base_command_builder.rb +1 -0
- data/lib/djin/memory_cache.rb +17 -0
- data/lib/djin/repositories/remote_config_repository.rb +86 -0
- data/lib/djin/root_cli_parser.rb +46 -0
- data/lib/djin/version.rb +1 -1
- metadata +45 -3
data/Vertofile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
verto_version '0.
|
1
|
+
verto_version '0.10.0'
|
2
2
|
|
3
3
|
config {
|
4
4
|
version.prefix = 'v' # Adds a version_prefix
|
@@ -12,28 +12,21 @@ context(branch('master')) {
|
|
12
12
|
}
|
13
13
|
|
14
14
|
before_tag_creation {
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
puts "---------------------------"
|
20
|
-
version_changes = "## #{new_version} - #{Time.now.strftime('%d/%m/%Y')}\n#{version_changes}\n"
|
21
|
-
exit unless confirm("Create new Realease?\n" \
|
22
|
-
"---------------------------\n" \
|
23
|
-
"#{version_changes}" \
|
24
|
-
"---------------------------\n"
|
25
|
-
)
|
26
|
-
|
27
|
-
# CHANGELOG
|
28
|
-
file('CHANGELOG.md').prepend(version_changes)
|
15
|
+
update_changelog(with: :merged_pull_requests_with_bracketed_labels,
|
16
|
+
confirmation: true,
|
17
|
+
filename: 'CHANGELOG.md')
|
18
|
+
|
29
19
|
git!('add CHANGELOG.md')
|
30
20
|
|
31
|
-
|
32
|
-
|
33
|
-
|
21
|
+
files_to_change_version_once = %w[lib/djin/version.rb djin.yml] + Dir['examples/**/*.yml'] + Dir['spec/support/fixtures/**/*.yml']
|
22
|
+
|
23
|
+
files_to_change_version_once.each do |filename|
|
24
|
+
file(filename).replace(latest_version.to_s, new_version.to_s)
|
25
|
+
end
|
26
|
+
|
34
27
|
file('README.md').replace_all(latest_version.to_s, new_version.to_s)
|
35
28
|
|
36
|
-
git!(
|
29
|
+
git!("add #{files_to_change_version_once.join(' ')} README.md")
|
37
30
|
|
38
31
|
sh!('bundle install')
|
39
32
|
sh!('rake install')
|
data/djin.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
# Specify which files should be added to the gem when it is released.
|
22
22
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
23
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
24
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|docker)/}) }
|
25
25
|
end
|
26
26
|
spec.bindir = 'exe'
|
27
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -31,6 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_dependency 'dry-equalizer', '~> 0.3.0'
|
32
32
|
spec.add_dependency 'dry-struct', '~> 1.3.0'
|
33
33
|
spec.add_dependency 'dry-validation', '~> 1.5.1'
|
34
|
+
spec.add_dependency 'git', '~> 1.8.1'
|
34
35
|
spec.add_dependency 'mustache', '~> 1.1.1'
|
35
36
|
spec.add_dependency 'vseries', '~> 0.1.0'
|
36
37
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
@@ -38,4 +39,5 @@ Gem::Specification.new do |spec|
|
|
38
39
|
spec.add_development_dependency 'rake', '~> 13.0'
|
39
40
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
40
41
|
spec.add_development_dependency 'rubocop'
|
42
|
+
spec.add_development_dependency 'simplecov', '~> 0.17.0'
|
41
43
|
end
|
data/djin.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
djin_version: '0.
|
1
|
+
djin_version: '0.11.2'
|
2
2
|
|
3
3
|
_default_run_options: &default_run_options
|
4
4
|
options: "--rm --entrypoint=''"
|
@@ -9,11 +9,21 @@ tasks:
|
|
9
9
|
docker-compose:
|
10
10
|
service: app
|
11
11
|
run:
|
12
|
-
commands: "
|
12
|
+
commands: "rspec {{args}}"
|
13
13
|
<<: *default_run_options
|
14
14
|
aliases:
|
15
15
|
- rspec
|
16
16
|
|
17
|
+
lint:
|
18
|
+
description: Lint
|
19
|
+
docker-compose:
|
20
|
+
service: app
|
21
|
+
run:
|
22
|
+
commands: "rubocop {{args}}"
|
23
|
+
<<: *default_run_options
|
24
|
+
aliases:
|
25
|
+
- rubocop
|
26
|
+
|
17
27
|
sh:
|
18
28
|
description: Enter app service shell
|
19
29
|
docker-compose:
|
@@ -31,5 +41,6 @@ tasks:
|
|
31
41
|
release:
|
32
42
|
local:
|
33
43
|
run:
|
44
|
+
- (source ~/.zshrc || true)
|
34
45
|
- verto tag up {{args}}
|
35
46
|
- bundle exec rake release
|
data/docker-compose.yml
CHANGED
@@ -1,6 +1,20 @@
|
|
1
|
-
version:
|
1
|
+
version: "3.9"
|
2
|
+
|
2
3
|
services:
|
3
4
|
app:
|
4
|
-
build:
|
5
|
+
build:
|
6
|
+
context: .
|
7
|
+
target: dev
|
8
|
+
entrypoint: 'sh docker-entrypoint.sh'
|
9
|
+
command: 'djin'
|
10
|
+
tty: true
|
11
|
+
stdin_open: true
|
5
12
|
volumes:
|
6
13
|
- .:/usr/src/djin
|
14
|
+
depends_on:
|
15
|
+
- gitserver
|
16
|
+
|
17
|
+
gitserver:
|
18
|
+
image: catks/gitserver-http:0.1.0
|
19
|
+
volumes:
|
20
|
+
- ./docker/git_server/repos/:/var/lib/initial/
|
data/examples/djin.yml
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
---
|
2
|
-
djin_version: '0.
|
2
|
+
djin_version: '0.11.2'
|
3
|
+
|
4
|
+
include:
|
5
|
+
- file: 'djin_lib/test.yml'
|
6
|
+
context:
|
7
|
+
variables:
|
8
|
+
namespace: 'test:'
|
9
|
+
|
10
|
+
- file: 'djin_lib/test.yml'
|
11
|
+
context:
|
12
|
+
variables:
|
13
|
+
namespace: 'test2:'
|
14
|
+
|
3
15
|
|
4
16
|
tasks:
|
5
17
|
default:
|
@@ -7,12 +19,6 @@ tasks:
|
|
7
19
|
image: "ruby:2.5"
|
8
20
|
run:
|
9
21
|
- "ruby -e 'puts \\\" Hello\\\"'"
|
10
|
-
test:
|
11
|
-
docker-compose:
|
12
|
-
service: app
|
13
|
-
run:
|
14
|
-
commands: rspec
|
15
|
-
options: "--rm"
|
16
22
|
|
17
23
|
script:
|
18
24
|
docker:
|
@@ -0,0 +1,17 @@
|
|
1
|
+
djin_version: '0.8.0'
|
2
|
+
|
3
|
+
tasks:
|
4
|
+
"{{namespace}}:ssh":
|
5
|
+
local:
|
6
|
+
run:
|
7
|
+
- ssh {{ssh_user}}@{{host}}
|
8
|
+
|
9
|
+
"{{namespace}}:restart":
|
10
|
+
local:
|
11
|
+
run:
|
12
|
+
- ssh -t {{ssh_user}}@{{host}} restart
|
13
|
+
|
14
|
+
"{{namespace}}:logs":
|
15
|
+
local:
|
16
|
+
run:
|
17
|
+
- ssh -t {{ssh_user}}@{{host}} tail -f /var/log/my_log
|
@@ -0,0 +1,22 @@
|
|
1
|
+
djin_version: '0.11.2'
|
2
|
+
|
3
|
+
include:
|
4
|
+
- file: '.djin/server_tasks.yml'
|
5
|
+
context:
|
6
|
+
variables:
|
7
|
+
namespace: host1
|
8
|
+
host: host1.com
|
9
|
+
ssh_user: my_user
|
10
|
+
|
11
|
+
- file: '.djin/server_tasks.yml'
|
12
|
+
context:
|
13
|
+
variables:
|
14
|
+
namespace: host2
|
15
|
+
host: host2.com
|
16
|
+
ssh_user: my_user
|
17
|
+
|
18
|
+
tasks:
|
19
|
+
hello_command:
|
20
|
+
local:
|
21
|
+
run:
|
22
|
+
- echo 'Hello Djin'
|
data/lib/djin.rb
CHANGED
@@ -8,44 +8,94 @@ require 'dry-validation'
|
|
8
8
|
require 'vseries'
|
9
9
|
require 'dry/cli'
|
10
10
|
require 'mustache'
|
11
|
+
require 'optparse'
|
12
|
+
require 'git'
|
11
13
|
require 'djin/extensions/hash_extensions'
|
14
|
+
require 'djin/extensions/object_extensions'
|
12
15
|
require 'djin/entities/types'
|
13
16
|
require 'djin/entities/task'
|
14
|
-
require 'djin/entities/
|
17
|
+
require 'djin/entities/include_config.rb'
|
18
|
+
require 'djin/entities/main_config'
|
15
19
|
require 'djin/interpreter/base_command_builder'
|
16
20
|
require 'djin/interpreter/docker_command_builder'
|
17
21
|
require 'djin/interpreter/docker_compose_command_builder'
|
18
22
|
require 'djin/interpreter/local_command_builder'
|
19
23
|
require 'djin/interpreter'
|
24
|
+
require 'djin/include_resolver'
|
20
25
|
require 'djin/config_loader'
|
21
26
|
require 'djin/executor'
|
27
|
+
require 'djin/root_cli_parser'
|
22
28
|
require 'djin/cli'
|
23
29
|
require 'djin/task_contract'
|
24
30
|
require 'djin/repositories/task_repository'
|
31
|
+
require 'djin/repositories/remote_config_repository'
|
32
|
+
require 'djin/memory_cache'
|
25
33
|
|
26
34
|
module Djin
|
27
35
|
class Error < StandardError; end
|
28
36
|
|
29
|
-
|
30
|
-
abort 'Error: djin.yml not found' unless path.exist?
|
37
|
+
using Djin::ObjectExtensions
|
31
38
|
|
32
|
-
|
39
|
+
class << self
|
40
|
+
def load_tasks!(*file_paths)
|
41
|
+
files = file_paths.presence || RootCliParser.parse![:files] || ['djin.yml']
|
33
42
|
|
34
|
-
|
35
|
-
tasks = Interpreter.load!(file_config)
|
43
|
+
file_config = ConfigLoader.load_files!(*files)
|
36
44
|
|
37
|
-
|
38
|
-
|
39
|
-
rescue Djin::Interpreter::InvalidConfigurationError => e
|
40
|
-
error_name = e.class.name.split('::').last
|
41
|
-
abort("[#{error_name}] #{e.message}")
|
42
|
-
end
|
45
|
+
# TODO: Make all tasks be under 'tasks' key, passing only the tasks here
|
46
|
+
tasks = Interpreter.load!(file_config)
|
43
47
|
|
44
|
-
|
45
|
-
|
46
|
-
|
48
|
+
@task_repository = TaskRepository.new(tasks)
|
49
|
+
|
50
|
+
remote_configs = file_config.include_configs.select { |f| f.type == :remote }
|
51
|
+
@remote_config_repository = RemoteConfigRepository.new(remote_configs)
|
52
|
+
|
53
|
+
CLI.load_tasks!(tasks)
|
54
|
+
rescue Djin::Interpreter::InvalidConfigurationError => e
|
55
|
+
error_name = e.class.name.split('::').last
|
56
|
+
abort("[#{error_name}] #{e.message}")
|
57
|
+
end
|
58
|
+
|
59
|
+
def tasks
|
60
|
+
task_repository.all
|
61
|
+
end
|
62
|
+
|
63
|
+
def task_repository
|
64
|
+
@task_repository ||= TaskRepository.new
|
65
|
+
end
|
66
|
+
|
67
|
+
def remote_config_repository
|
68
|
+
@remote_config_repository ||= RemoteConfigRepository.new
|
69
|
+
end
|
70
|
+
|
71
|
+
def cache
|
72
|
+
@cache ||= MemoryCache.new
|
73
|
+
end
|
74
|
+
|
75
|
+
def root_path
|
76
|
+
Pathname.new File.expand_path(__dir__ + '/..')
|
77
|
+
end
|
78
|
+
|
79
|
+
def warn(message, type: 'WARNING')
|
80
|
+
stderr.puts "[#{type}] #{message}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def warn_once(message, type: 'WARNING')
|
84
|
+
return if warnings.include?(message)
|
85
|
+
|
86
|
+
warn(message, type: type)
|
87
|
+
|
88
|
+
warnings << message
|
89
|
+
end
|
90
|
+
|
91
|
+
def stderr
|
92
|
+
$stderr
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
47
96
|
|
48
|
-
|
49
|
-
|
97
|
+
def warnings
|
98
|
+
@warnings ||= []
|
99
|
+
end
|
50
100
|
end
|
51
101
|
end
|
data/lib/djin/cli.rb
CHANGED
@@ -28,6 +28,42 @@ module Djin
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
class File < Dry::CLI::Command
|
32
|
+
desc 'Specify a djin file to load (default: djin.yml)'
|
33
|
+
argument :filepath, required: true, desc: 'The file path to load'
|
34
|
+
|
35
|
+
def call(filename:, **)
|
36
|
+
# The actual behaviour is on RootCliParser
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module RemoteConfig
|
41
|
+
class Fetch < Dry::CLI::Command
|
42
|
+
desc 'Fetchs missing remote configs'
|
43
|
+
|
44
|
+
def call(*)
|
45
|
+
Djin.remote_config_repository.fetch_all
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Clear < Dry::CLI::Command
|
50
|
+
desc 'clear downloaded remote configs'
|
51
|
+
option :all,
|
52
|
+
type: :boolean,
|
53
|
+
default: false,
|
54
|
+
desc: 'Remove all remote configs, not only the ones referenced in the current djin file'
|
55
|
+
|
56
|
+
def call(all:)
|
57
|
+
return Djin.remote_config_repository.clear_all if all
|
58
|
+
|
59
|
+
Djin.remote_config_repository.clear
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
register '-f', File, aliases: ['--file']
|
31
65
|
register '--version', Version, aliases: ['-v']
|
66
|
+
register 'remote-config fetch', RemoteConfig::Fetch
|
67
|
+
register 'remote-config clear', RemoteConfig::Clear
|
32
68
|
end
|
33
69
|
end
|
data/lib/djin/config_loader.rb
CHANGED
@@ -4,20 +4,38 @@ module Djin
|
|
4
4
|
# TODO: Refactor this class to be the Interpreter
|
5
5
|
# class and use the current interpreter as
|
6
6
|
# a TaskLoader
|
7
|
+
|
8
|
+
# rubocop:disable Metrics/ClassLength
|
7
9
|
class ConfigLoader
|
8
10
|
using Djin::HashExtensions
|
9
|
-
RESERVED_WORDS = %w[djin_version variables tasks].freeze
|
11
|
+
RESERVED_WORDS = %w[djin_version variables tasks include].freeze
|
12
|
+
|
13
|
+
# Change Base Error
|
14
|
+
FileNotFoundError = Class.new(Interpreter::InvalidConfigurationError)
|
15
|
+
|
16
|
+
def self.load_files!(*files, runtime_config: {}, base_directory: '.')
|
17
|
+
files.map do |file_path|
|
18
|
+
ConfigLoader.load!(file_path, runtime_config: runtime_config, base_directory: base_directory)
|
19
|
+
end&.reduce(:deep_merge)
|
20
|
+
end
|
10
21
|
|
11
|
-
def self.load!(
|
12
|
-
new(
|
22
|
+
def self.load!(template_file_path, runtime_config: {}, base_directory: '.')
|
23
|
+
new(template_file_path, runtime_config: runtime_config, base_directory: base_directory).load!
|
13
24
|
end
|
14
25
|
|
15
|
-
def initialize(
|
16
|
-
@
|
26
|
+
def initialize(template_file_path, runtime_config: {}, base_directory: '.')
|
27
|
+
@base_directory = Pathname.new(base_directory)
|
28
|
+
@template_file = @base_directory.join(template_file_path)
|
29
|
+
|
30
|
+
file_not_found!(@template_file) unless @template_file.exist?
|
31
|
+
|
32
|
+
@template_file_content = Djin.cache.fetch(@template_file.realpath.to_s) { @template_file.read }
|
33
|
+
@runtime_config = runtime_config
|
17
34
|
end
|
18
35
|
|
19
36
|
def load!
|
20
37
|
validate_version!
|
38
|
+
validate_missing_config!
|
21
39
|
|
22
40
|
file_config
|
23
41
|
end
|
@@ -25,52 +43,38 @@ module Djin
|
|
25
43
|
private
|
26
44
|
|
27
45
|
def file_config
|
28
|
-
|
46
|
+
MainConfig.new(
|
29
47
|
djin_version: version,
|
30
48
|
variables: variables,
|
31
49
|
tasks: tasks,
|
32
|
-
raw_tasks: raw_tasks
|
50
|
+
raw_tasks: raw_tasks,
|
51
|
+
include_configs: @include_configs || []
|
33
52
|
)
|
34
53
|
end
|
35
54
|
|
36
|
-
def raw_djin_config
|
37
|
-
@raw_djin_config ||= yaml_load(@template_file)
|
38
|
-
rescue Psych::SyntaxError => e
|
39
|
-
raise Interpreter::InvalidConfigFileError, e.message
|
40
|
-
end
|
41
|
-
|
42
|
-
def rendered_djin_config
|
43
|
-
@rendered_djin_config ||= begin
|
44
|
-
locals = env.merge(variables)
|
45
|
-
|
46
|
-
rendered_yaml = Mustache.render(@template_file,
|
47
|
-
args: args.join(' '),
|
48
|
-
args?: args.any?,
|
49
|
-
**locals)
|
50
|
-
yaml_load(rendered_yaml)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
55
|
def version
|
55
56
|
# TODO: Deprecates djin_version and use version instead
|
56
57
|
@version || raw_djin_config['djin_version']
|
57
58
|
end
|
58
59
|
|
59
60
|
def variables
|
60
|
-
@variables ||= raw_djin_config['variables']&.symbolize_keys || {}
|
61
|
+
@variables ||= included_variables.merge(raw_djin_config['variables']&.symbolize_keys || {})
|
61
62
|
end
|
62
63
|
|
63
64
|
def tasks
|
64
|
-
rendered_djin_config['tasks'] || legacy_tasks
|
65
|
+
included_tasks.merge(rendered_djin_config['tasks'] || legacy_tasks)
|
65
66
|
end
|
66
67
|
|
67
68
|
def raw_tasks
|
68
|
-
raw_djin_config['tasks'] || legacy_raw_tasks
|
69
|
+
included_raw_tasks.merge(raw_djin_config['tasks'] || legacy_raw_tasks)
|
69
70
|
end
|
70
71
|
|
71
72
|
def legacy_tasks
|
72
|
-
|
73
|
-
|
73
|
+
Djin.warn_once(
|
74
|
+
'Root tasks are deprecated and will be removed in Djin 1.0.0,' \
|
75
|
+
' put the tasks under \'tasks\' keyword',
|
76
|
+
type: 'DEPRECATED'
|
77
|
+
)
|
74
78
|
|
75
79
|
rendered_djin_config.except(*RESERVED_WORDS).reject { |task| task.start_with?('_') }
|
76
80
|
end
|
@@ -79,6 +83,57 @@ module Djin
|
|
79
83
|
raw_djin_config.except(*RESERVED_WORDS).reject { |task| task.start_with?('_') }
|
80
84
|
end
|
81
85
|
|
86
|
+
def included_variables
|
87
|
+
return {} unless included_config
|
88
|
+
|
89
|
+
included_config.variables
|
90
|
+
end
|
91
|
+
|
92
|
+
def included_tasks
|
93
|
+
return {} unless included_config
|
94
|
+
|
95
|
+
included_config.tasks
|
96
|
+
end
|
97
|
+
|
98
|
+
def included_raw_tasks
|
99
|
+
return {} unless included_config
|
100
|
+
|
101
|
+
included_config.raw_tasks
|
102
|
+
end
|
103
|
+
|
104
|
+
# TODO: Rename method
|
105
|
+
def included_config
|
106
|
+
@included_config ||= begin
|
107
|
+
present_include_configs&.map do |present_include|
|
108
|
+
ConfigLoader.load!(present_include.file, base_directory: @template_file.dirname,
|
109
|
+
# TODO: Rename to context_config
|
110
|
+
runtime_config: present_include.context)
|
111
|
+
end&.reduce(:deep_merge)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def present_include_configs
|
116
|
+
include_configs&.select(&:present?)
|
117
|
+
end
|
118
|
+
|
119
|
+
def missing_include_configs
|
120
|
+
include_configs&.select(&:missing?)
|
121
|
+
end
|
122
|
+
|
123
|
+
# TODO: Refactor to move include methods to a specific IncludeConfigLoader, maybe rename IncludeResolver
|
124
|
+
def include_configs
|
125
|
+
@include_configs ||= begin
|
126
|
+
# TODO: Rename the resolved variables
|
127
|
+
resolver = IncludeResolver.new(base_directory: @template_file.dirname)
|
128
|
+
|
129
|
+
include_djin_config = raw_djin_config['include'] || []
|
130
|
+
|
131
|
+
include_djin_config.map do |include_config|
|
132
|
+
resolver.call(include_config)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
82
137
|
def args
|
83
138
|
index = ARGV.index('--')
|
84
139
|
|
@@ -91,6 +146,24 @@ module Djin
|
|
91
146
|
@env ||= ENV.to_h.symbolize_keys
|
92
147
|
end
|
93
148
|
|
149
|
+
def raw_djin_config
|
150
|
+
@raw_djin_config ||= yaml_load(@template_file_content).deep_merge(@runtime_config)
|
151
|
+
rescue Psych::SyntaxError => e
|
152
|
+
raise Interpreter::InvalidConfigFileError, "File: #{@template_file.realpath}\n #{e.message}"
|
153
|
+
end
|
154
|
+
|
155
|
+
def rendered_djin_config
|
156
|
+
@rendered_djin_config ||= begin
|
157
|
+
locals = env.merge(variables)
|
158
|
+
|
159
|
+
rendered_yaml = Mustache.render(@template_file_content,
|
160
|
+
args: args.join(' '),
|
161
|
+
args?: args.any?,
|
162
|
+
**locals)
|
163
|
+
yaml_load(rendered_yaml).merge(@runtime_config)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
94
167
|
def yaml_load(text)
|
95
168
|
YAML.safe_load(text, [], [], true)
|
96
169
|
end
|
@@ -102,5 +175,26 @@ module Djin
|
|
102
175
|
|
103
176
|
raise Interpreter::VersionNotSupportedError, "Version #{version} is not supported, use #{Djin::VERSION} or higher"
|
104
177
|
end
|
178
|
+
|
179
|
+
def validate_missing_config!
|
180
|
+
missing_include_configs.each do |ic|
|
181
|
+
file_not_found!(ic.full_path) if ic.type == :local
|
182
|
+
|
183
|
+
missing_file_remote_error = "#{ic.git} exists but is missing %s," \
|
184
|
+
'if the file exists in upstream run djin remote-config fetch to fix'
|
185
|
+
|
186
|
+
file_not_found!(ic.full_path, missing_file_remote_error) if ic.type == :remote && ic.repository_fetched?
|
187
|
+
|
188
|
+
if ic.type == :remote
|
189
|
+
Djin.warn_once "Missing #{ic.git} with version '#{ic.version}', " \
|
190
|
+
'run `djin remote-config fetch` to fetch the config'
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def file_not_found!(filename, message = "File '%s' not found")
|
196
|
+
raise FileNotFoundError, message % filename
|
197
|
+
end
|
105
198
|
end
|
199
|
+
# rubocop:enable Metrics/ClassLength
|
106
200
|
end
|