djin 0.3.0 → 0.7.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/.github/workflows/ruby.yml +14 -0
- data/.rubocop.yml +8 -0
- data/.rubocop_todo.yml +17 -0
- data/CHANGELOG.md +20 -0
- data/Gemfile +3 -1
- data/Gemfile.lock +34 -10
- data/README.md +133 -32
- data/Rakefile +6 -4
- data/Vertofile +45 -0
- data/bin/console +4 -3
- data/djin.gemspec +26 -21
- data/djin.yml +28 -13
- data/examples/djin.yml +25 -23
- data/exe/djin +3 -0
- data/lib/djin.rb +31 -23
- data/lib/djin/cli.rb +5 -5
- data/lib/djin/config_loader.rb +106 -0
- data/lib/djin/entities/file_config.rb +17 -0
- data/lib/djin/entities/task.rb +4 -5
- data/lib/djin/entities/types.rb +2 -0
- data/lib/djin/executor.rb +2 -0
- data/lib/djin/extensions/hash_extensions.rb +7 -1
- data/lib/djin/interpreter.rb +15 -63
- data/lib/djin/interpreter/base_command_builder.rb +26 -0
- data/lib/djin/interpreter/docker_command_builder.rb +29 -0
- data/lib/djin/interpreter/docker_compose_command_builder.rb +17 -0
- data/lib/djin/interpreter/local_command_builder.rb +11 -0
- data/lib/djin/repositories/task_repository.rb +2 -0
- data/lib/djin/task_contract.rb +37 -7
- data/lib/djin/version.rb +3 -1
- metadata +62 -11
- data/lib/djin/extensions/custom_predicates.rb +0 -18
data/lib/djin/executor.rb
CHANGED
@@ -1,8 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Djin
|
2
4
|
module HashExtensions
|
3
5
|
refine Hash do
|
4
6
|
def except(*keys)
|
5
|
-
reject { |key,_| keys.include?(key) }
|
7
|
+
reject { |key, _| keys.include?(key) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def symbolize_keys
|
11
|
+
map { |key, value| [key.to_sym, value] }.to_h
|
6
12
|
end
|
7
13
|
end
|
8
14
|
end
|
data/lib/djin/interpreter.rb
CHANGED
@@ -1,34 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Djin
|
2
4
|
class Interpreter
|
3
5
|
using Djin::HashExtensions
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
+
# TODO: Move Errors to ConfigLoader
|
7
8
|
InvalidConfigurationError = Class.new(StandardError)
|
9
|
+
InvalidConfigFileError = Class.new(InvalidConfigurationError)
|
8
10
|
MissingVersionError = Class.new(InvalidConfigurationError)
|
9
11
|
VersionNotSupportedError = Class.new(InvalidConfigurationError)
|
10
12
|
InvalidSyntaxError = Class.new(InvalidConfigurationError)
|
11
13
|
|
12
14
|
class << self
|
13
|
-
def load!(
|
14
|
-
version = params['djin_version']
|
15
|
-
raise MissingVersionError, 'Missing djin_version' unless version
|
16
|
-
raise VersionNotSupportedError, "Version #{version} is not supported, use #{Djin::VERSION} or higher" unless version_supported?(version)
|
17
|
-
|
18
|
-
tasks_params = params.except(*RESERVED_WORDS).reject { |task| task.start_with?('_') }
|
15
|
+
def load!(file_config)
|
19
16
|
contract = TaskContract.new
|
20
17
|
|
21
|
-
|
18
|
+
file_config.tasks.map do |task_name, options|
|
22
19
|
result = contract.call(options)
|
23
20
|
|
24
21
|
raise InvalidSyntaxError, { task_name.to_sym => result.errors.to_h } if result.failure?
|
25
22
|
|
26
23
|
command, build_command = build_commands(options, task_name: task_name)
|
27
24
|
|
25
|
+
raw_command, = build_commands(file_config.raw_tasks[task_name], task_name: task_name)
|
26
|
+
|
28
27
|
task_params = {
|
29
28
|
name: task_name,
|
30
29
|
build_command: build_command,
|
30
|
+
description: options['description'] || "Runs: #{raw_command}",
|
31
31
|
command: command,
|
32
|
+
raw_command: raw_command,
|
32
33
|
depends_on: options['depends_on']
|
33
34
|
}.compact
|
34
35
|
|
@@ -42,62 +43,13 @@ module Djin
|
|
42
43
|
# Validate that only one ot the two is passed
|
43
44
|
docker_params = params['docker']
|
44
45
|
docker_compose_params = params['docker-compose']
|
46
|
+
local_params = params['local']
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
def build_docker_commands(params, task_name:)
|
51
|
-
current_folder_name = Pathname.getwd.basename.to_s
|
52
|
-
image = params['image'] || "djin_#{current_folder_name}_#{task_name}"
|
53
|
-
|
54
|
-
build_params = params['build']
|
55
|
-
|
56
|
-
if build_params.is_a?(Hash)
|
57
|
-
build_context = build_params['context']
|
58
|
-
build_options = build_params['options']
|
59
|
-
end
|
60
|
-
|
61
|
-
build_context ||= build_params
|
62
|
-
|
63
|
-
run_command, run_options = build_run_params(params['run'])
|
64
|
-
|
65
|
-
command = %Q{docker run #{run_options} #{image} sh -c "#{run_command}"}.squeeze(' ')
|
66
|
-
|
67
|
-
build_command = "docker build #{build_context} #{build_options} -t #{image}".squeeze(' ') if build_context
|
68
|
-
|
69
|
-
[command, build_command]
|
70
|
-
end
|
71
|
-
|
72
|
-
def build_docker_compose_commands(params)
|
73
|
-
service = params['service']
|
74
|
-
|
75
|
-
compose_options = params['options']
|
76
|
-
|
77
|
-
run_command, run_options = build_run_params(params['run'])
|
78
|
-
|
79
|
-
[%Q{docker-compose #{compose_options} run #{run_options} #{service} sh -c "#{run_command}"}.squeeze(' '), nil]
|
80
|
-
end
|
81
|
-
|
82
|
-
def build_run_params(run_params)
|
83
|
-
run_command = run_params
|
84
|
-
|
85
|
-
if run_params.is_a?(Hash)
|
86
|
-
run_command = run_params['commands']
|
87
|
-
run_options = run_params['options']
|
88
|
-
end
|
89
|
-
|
90
|
-
run_command = run_command.join(' && ') if run_command.is_a?(Array)
|
91
|
-
|
92
|
-
[run_command, run_options]
|
93
|
-
end
|
94
|
-
|
95
|
-
def validate_version!(version)
|
96
|
-
|
97
|
-
end
|
48
|
+
# TODO: Refactor to use chain of responsability
|
49
|
+
return DockerCommandBuilder.call(docker_params, task_name: task_name) if docker_params
|
50
|
+
return DockerComposeCommandBuilder.call(docker_compose_params) if docker_compose_params
|
98
51
|
|
99
|
-
|
100
|
-
Vseries::SemanticVersion.new(Djin::VERSION) >= Vseries::SemanticVersion.new(version)
|
52
|
+
LocalCommandBuilder.call(local_params) if local_params
|
101
53
|
end
|
102
54
|
end
|
103
55
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Djin
|
4
|
+
class Interpreter
|
5
|
+
class BaseCommandBuilder
|
6
|
+
def self.call(*options)
|
7
|
+
new.call(*options)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def build_run_params(run_params)
|
13
|
+
run_command = run_params
|
14
|
+
|
15
|
+
if run_params.is_a?(Hash)
|
16
|
+
run_command = run_params['commands']
|
17
|
+
run_options = run_params['options']
|
18
|
+
end
|
19
|
+
|
20
|
+
run_command = run_command.join(' && ') if run_command.is_a?(Array)
|
21
|
+
|
22
|
+
[run_command, run_options]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Djin
|
4
|
+
class Interpreter
|
5
|
+
class DockerCommandBuilder < BaseCommandBuilder
|
6
|
+
def call(params, task_name:)
|
7
|
+
current_folder_name = Pathname.getwd.basename.to_s
|
8
|
+
image = params['image'] || "djin_#{current_folder_name}_#{task_name}"
|
9
|
+
|
10
|
+
build_params = params['build']
|
11
|
+
|
12
|
+
if build_params.is_a?(Hash)
|
13
|
+
build_context = build_params['context']
|
14
|
+
build_options = build_params['options']
|
15
|
+
end
|
16
|
+
|
17
|
+
build_context ||= build_params
|
18
|
+
|
19
|
+
run_command, run_options = build_run_params(params['run'])
|
20
|
+
|
21
|
+
command = %(docker run #{run_options} #{image} sh -c "#{run_command}").squeeze(' ')
|
22
|
+
|
23
|
+
build_command = "docker build #{build_context} #{build_options} -t #{image}".squeeze(' ') if build_context
|
24
|
+
|
25
|
+
[command, build_command]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Djin
|
4
|
+
class Interpreter
|
5
|
+
class DockerComposeCommandBuilder < BaseCommandBuilder
|
6
|
+
def call(params, **_)
|
7
|
+
service = params['service']
|
8
|
+
|
9
|
+
compose_options = params['options']
|
10
|
+
|
11
|
+
run_command, run_options = build_run_params(params['run'])
|
12
|
+
|
13
|
+
[%(docker-compose #{compose_options} run #{run_options} #{service} sh -c "#{run_command}").squeeze(' '), nil]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/djin/task_contract.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Djin
|
2
4
|
class TaskContract < Dry::Validation::Contract
|
3
|
-
NOT_EMPTY = ->
|
4
|
-
OK = ->
|
5
|
+
NOT_EMPTY = ->(value) { !value.empty? }
|
6
|
+
OK = ->(_) { true }
|
7
|
+
NOT_OK = ->(_) { false }
|
5
8
|
|
6
9
|
BuildSchema = Dry::Schema.Params do
|
7
10
|
required(:context).filled(:string)
|
@@ -13,6 +16,10 @@ module Djin
|
|
13
16
|
required(:options).filled(:string)
|
14
17
|
end
|
15
18
|
|
19
|
+
RunLocalSchema = Dry::Schema.Params do
|
20
|
+
required(:commands).filled
|
21
|
+
end
|
22
|
+
|
16
23
|
DockerSchema = Dry::Schema.Params do
|
17
24
|
optional(:image).maybe(:string)
|
18
25
|
optional(:build)
|
@@ -25,32 +32,49 @@ module Djin
|
|
25
32
|
required(:run).filled
|
26
33
|
end
|
27
34
|
|
35
|
+
LocalSchema = Dry::Schema.Params do
|
36
|
+
required(:run).filled
|
37
|
+
end
|
38
|
+
|
28
39
|
params do
|
29
40
|
optional(:docker).filled do
|
30
41
|
hash(DockerSchema)
|
31
42
|
end
|
43
|
+
|
32
44
|
optional(:"docker-compose").filled do
|
33
45
|
hash(DockerComposeSchema)
|
34
46
|
end
|
35
47
|
|
48
|
+
optional(:local).filled do
|
49
|
+
hash(LocalSchema)
|
50
|
+
end
|
51
|
+
|
36
52
|
optional(:depends_on).each(:str?)
|
37
53
|
end
|
38
54
|
|
39
|
-
rule(:docker, :"docker-compose", :depends_on) do
|
40
|
-
|
55
|
+
rule(:docker, :"docker-compose", :local, :depends_on) do
|
56
|
+
unless values[:docker] || values[:"docker-compose"] || values[:depends_on] || values[:local]
|
57
|
+
key.failure('docker, docker-compose, local or depends_on key is required')
|
58
|
+
end
|
41
59
|
end
|
42
60
|
|
43
|
-
rule(:depends_on, :'docker-compose',docker: [
|
44
|
-
key.failure('image or build param is required for docker tasks') unless values.dig(:docker, :image) ||
|
61
|
+
rule(:depends_on, :'docker-compose', :local, docker: %i[image build]) do
|
62
|
+
key.failure('image or build param is required for docker tasks') unless values.dig(:docker, :image) ||
|
63
|
+
values.dig(:docker, :build) ||
|
64
|
+
values[:'docker-compose'] ||
|
65
|
+
values[:depends_on] ||
|
66
|
+
values.dig(:local, :run)
|
45
67
|
end
|
46
68
|
|
69
|
+
# TODO: Extract validations to command builders
|
70
|
+
|
47
71
|
rule(docker: :build) do
|
48
72
|
result, errors = validate_for(value, Hash => BuildSchema, String => NOT_EMPTY, NilClass => OK)
|
49
73
|
|
50
74
|
key.failure(errors) unless result
|
51
75
|
end
|
52
76
|
|
53
|
-
rule(
|
77
|
+
rule('docker-compose': :run) do
|
54
78
|
result, errors = validate_for(value, Hash => RunSchema, Array => NOT_EMPTY, NilClass => OK)
|
55
79
|
|
56
80
|
key.failure(errors) unless result
|
@@ -62,6 +86,12 @@ module Djin
|
|
62
86
|
key.failure(errors) unless result
|
63
87
|
end
|
64
88
|
|
89
|
+
rule(local: :run) do
|
90
|
+
result, errors = validate_for(value, Hash => RunLocalSchema, Array => NOT_EMPTY, NilClass => OK)
|
91
|
+
|
92
|
+
key.failure(errors) unless result
|
93
|
+
end
|
94
|
+
|
65
95
|
private
|
66
96
|
|
67
97
|
def validate_for(value, validations)
|
data/lib/djin/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: djin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carlos Atkinson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: dry-cli
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.6.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.6.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dry-equalizer
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.3.0
|
13
41
|
- !ruby/object:Gem::Dependency
|
14
42
|
name: dry-struct
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -25,33 +53,33 @@ dependencies:
|
|
25
53
|
- !ruby/object:Gem::Version
|
26
54
|
version: 1.3.0
|
27
55
|
- !ruby/object:Gem::Dependency
|
28
|
-
name: dry-
|
56
|
+
name: dry-validation
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
30
58
|
requirements:
|
31
59
|
- - "~>"
|
32
60
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
61
|
+
version: 1.5.1
|
34
62
|
type: :runtime
|
35
63
|
prerelease: false
|
36
64
|
version_requirements: !ruby/object:Gem::Requirement
|
37
65
|
requirements:
|
38
66
|
- - "~>"
|
39
67
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
68
|
+
version: 1.5.1
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
70
|
+
name: mustache
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
44
72
|
requirements:
|
45
73
|
- - "~>"
|
46
74
|
- !ruby/object:Gem::Version
|
47
|
-
version: 1.
|
75
|
+
version: 1.1.1
|
48
76
|
type: :runtime
|
49
77
|
prerelease: false
|
50
78
|
version_requirements: !ruby/object:Gem::Requirement
|
51
79
|
requirements:
|
52
80
|
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version: 1.
|
82
|
+
version: 1.1.1
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: vseries
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +108,20 @@ dependencies:
|
|
80
108
|
- - "~>"
|
81
109
|
- !ruby/object:Gem::Version
|
82
110
|
version: '2.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: byebug
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
83
125
|
- !ruby/object:Gem::Dependency
|
84
126
|
name: rake
|
85
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,7 +151,7 @@ dependencies:
|
|
109
151
|
- !ruby/object:Gem::Version
|
110
152
|
version: '3.0'
|
111
153
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
154
|
+
name: rubocop
|
113
155
|
requirement: !ruby/object:Gem::Requirement
|
114
156
|
requirements:
|
115
157
|
- - ">="
|
@@ -133,6 +175,8 @@ files:
|
|
133
175
|
- ".github/workflows/ruby.yml"
|
134
176
|
- ".gitignore"
|
135
177
|
- ".rspec"
|
178
|
+
- ".rubocop.yml"
|
179
|
+
- ".rubocop_todo.yml"
|
136
180
|
- ".travis.yml"
|
137
181
|
- CHANGELOG.md
|
138
182
|
- Dockerfile
|
@@ -141,6 +185,7 @@ files:
|
|
141
185
|
- LICENSE.txt
|
142
186
|
- README.md
|
143
187
|
- Rakefile
|
188
|
+
- Vertofile
|
144
189
|
- bin/console
|
145
190
|
- bin/setup
|
146
191
|
- djin.gemspec
|
@@ -150,12 +195,17 @@ files:
|
|
150
195
|
- exe/djin
|
151
196
|
- lib/djin.rb
|
152
197
|
- lib/djin/cli.rb
|
198
|
+
- lib/djin/config_loader.rb
|
199
|
+
- lib/djin/entities/file_config.rb
|
153
200
|
- lib/djin/entities/task.rb
|
154
201
|
- lib/djin/entities/types.rb
|
155
202
|
- lib/djin/executor.rb
|
156
|
-
- lib/djin/extensions/custom_predicates.rb
|
157
203
|
- lib/djin/extensions/hash_extensions.rb
|
158
204
|
- lib/djin/interpreter.rb
|
205
|
+
- lib/djin/interpreter/base_command_builder.rb
|
206
|
+
- lib/djin/interpreter/docker_command_builder.rb
|
207
|
+
- lib/djin/interpreter/docker_compose_command_builder.rb
|
208
|
+
- lib/djin/interpreter/local_command_builder.rb
|
159
209
|
- lib/djin/repositories/task_repository.rb
|
160
210
|
- lib/djin/task_contract.rb
|
161
211
|
- lib/djin/version.rb
|
@@ -178,7 +228,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
178
228
|
- !ruby/object:Gem::Version
|
179
229
|
version: '0'
|
180
230
|
requirements: []
|
181
|
-
|
231
|
+
rubyforge_project:
|
232
|
+
rubygems_version: 2.7.6
|
182
233
|
signing_key:
|
183
234
|
specification_version: 4
|
184
235
|
summary: djin is a make-like utility for docker containers
|