djin 0.1.1 → 0.6.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.
@@ -1,23 +1,34 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Djin
2
4
  class Interpreter
3
5
  using Djin::HashExtensions
4
6
 
5
- RESERVED_WORDS = %w[_version _default_options].freeze
6
-
7
- InvalidSyntax = Class.new(StandardError)
7
+ # TODO: Move Errors to ConfigLoader
8
+ InvalidConfigurationError = Class.new(StandardError)
9
+ MissingVersionError = Class.new(InvalidConfigurationError)
10
+ VersionNotSupportedError = Class.new(InvalidConfigurationError)
11
+ InvalidSyntaxError = Class.new(InvalidConfigurationError)
8
12
 
9
13
  class << self
10
- def load!(params)
11
- task_params = params.except(*RESERVED_WORDS)
14
+ def load!(tasks_params)
12
15
  contract = TaskContract.new
13
16
 
14
- task_params.map do |task_name, options|
17
+ tasks_params.map do |task_name, options|
15
18
  result = contract.call(options)
16
19
 
17
- raise InvalidSyntax, result.errors.to_h if result.failure?
20
+ raise InvalidSyntaxError, { task_name.to_sym => result.errors.to_h } if result.failure?
18
21
 
19
22
  command, build_command = build_commands(options, task_name: task_name)
20
- Djin::Task.new(name: task_name, build_command: build_command, command: command)
23
+
24
+ task_params = {
25
+ name: task_name,
26
+ build_command: build_command,
27
+ command: command,
28
+ depends_on: options['depends_on']
29
+ }.compact
30
+
31
+ Djin::Task.new(**task_params)
21
32
  end
22
33
  end
23
34
 
@@ -27,54 +38,13 @@ module Djin
27
38
  # Validate that only one ot the two is passed
28
39
  docker_params = params['docker']
29
40
  docker_compose_params = params['docker-compose']
41
+ local_params = params['local']
30
42
 
31
- return build_docker_commands(docker_params, task_name: task_name) if docker_params
32
- build_docker_compose_commands(docker_compose_params) if docker_compose_params
33
- end
34
-
35
- def build_docker_commands(params, task_name:)
36
- current_folder_name = Pathname.getwd.basename.to_s
37
- image = params['image'] || "djin_#{current_folder_name}_#{task_name}"
38
-
39
- build_params = params['build']
40
-
41
- if build_params.is_a?(Hash)
42
- build_context = build_params['context']
43
- build_options = build_params['options']
44
- end
45
-
46
- build_context ||= build_params
47
-
48
- run_command, run_options = build_run_params(params['run'])
49
-
50
- command = %Q{docker run #{run_options} #{image} sh -c "#{run_command}"}.squeeze(' ')
51
-
52
- build_command = "docker build #{build_context} #{build_options} -t #{image}".squeeze(' ') if build_context
53
-
54
- [command, build_command]
55
- end
56
-
57
- def build_docker_compose_commands(params)
58
- service = params['service']
59
-
60
- compose_options = params['options']
61
-
62
- run_command, run_options = build_run_params(params['run'])
63
-
64
- [%Q{docker-compose #{compose_options} run #{run_options} #{service} sh -c "#{run_command}"}.squeeze(' '), nil]
65
- end
66
-
67
- def build_run_params(run_params)
68
- run_command = run_params
69
-
70
- if run_params.is_a?(Hash)
71
- run_command = run_params['commands']
72
- run_options = run_params['options']
73
- end
74
-
75
- run_command = run_command.join(' && ') if run_command.is_a?(Array)
43
+ # TODO: Refactor to use chain of responsability
44
+ return DockerCommandBuilder.call(docker_params, task_name: task_name) if docker_params
45
+ return DockerComposeCommandBuilder.call(docker_compose_params) if docker_compose_params
76
46
 
77
- [run_command, run_options]
47
+ LocalCommandBuilder.call(local_params) if local_params
78
48
  end
79
49
  end
80
50
  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
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Djin
4
+ class Interpreter
5
+ class LocalCommandBuilder < BaseCommandBuilder
6
+ def call(params, **_)
7
+ build_run_params(params['run'])
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TaskRepository
4
+ def initialize(tasks = [])
5
+ @tasks = tasks
6
+ end
7
+
8
+ def add(*tasks)
9
+ @tasks += tasks
10
+ end
11
+
12
+ def all
13
+ @tasks
14
+ end
15
+
16
+ def find_by_names(names)
17
+ @tasks.select { |task| names.include?(task.name) }
18
+ end
19
+ end
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Djin
2
4
  class TaskContract < Dry::Validation::Contract
3
- NOT_EMPTY = -> (value) { ! value.empty? }
4
- OK = -> (_) { true }
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,30 +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
47
+
48
+ optional(:local).filled do
49
+ hash(LocalSchema)
50
+ end
51
+
52
+ optional(:depends_on).each(:str?)
35
53
  end
36
54
 
37
- rule(:docker, :"docker-compose") do
38
- key.failure('docker or docker-compose key is required') unless values[:docker] || values[:"docker-compose"]
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
39
59
  end
40
60
 
41
- rule(:'docker-compose',docker: [:image, :build]) do
42
- key.failure('image or build param is required for docker tasks') unless values.dig(:docker, :image) || values.dig(:docker, :build) || values[:'docker-compose']
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)
43
67
  end
44
68
 
69
+ # TODO: Extract validations to command builders
70
+
45
71
  rule(docker: :build) do
46
72
  result, errors = validate_for(value, Hash => BuildSchema, String => NOT_EMPTY, NilClass => OK)
47
73
 
48
74
  key.failure(errors) unless result
49
75
  end
50
76
 
51
- rule(:'docker-compose' => :run) do
77
+ rule('docker-compose': :run) do
52
78
  result, errors = validate_for(value, Hash => RunSchema, Array => NOT_EMPTY, NilClass => OK)
53
79
 
54
80
  key.failure(errors) unless result
@@ -60,6 +86,12 @@ module Djin
60
86
  key.failure(errors) unless result
61
87
  end
62
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
+
63
95
  private
64
96
 
65
97
  def validate_for(value, validations)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Djin
2
- VERSION = "0.1.1"
4
+ VERSION = '0.6.0'
3
5
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: djin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.6.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-03-13 00:00:00.000000000 Z
11
+ date: 2020-07-23 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
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: dry-struct
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -25,33 +39,47 @@ dependencies:
25
39
  - !ruby/object:Gem::Version
26
40
  version: 1.3.0
27
41
  - !ruby/object:Gem::Dependency
28
- name: dry-cli
42
+ name: dry-validation
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: 0.5.0
47
+ version: 1.5.1
34
48
  type: :runtime
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: 0.5.0
54
+ version: 1.5.1
41
55
  - !ruby/object:Gem::Dependency
42
- name: dry-validation
56
+ name: mustache
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: 1.5.0
61
+ version: 1.1.1
48
62
  type: :runtime
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: 1.5.0
68
+ version: 1.1.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: vseries
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.1.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.1.0
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: bundler
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -66,20 +94,34 @@ dependencies:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
96
  version: '2.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
69
111
  - !ruby/object:Gem::Dependency
70
112
  name: rake
71
113
  requirement: !ruby/object:Gem::Requirement
72
114
  requirements:
73
115
  - - "~>"
74
116
  - !ruby/object:Gem::Version
75
- version: '10.0'
117
+ version: '13.0'
76
118
  type: :development
77
119
  prerelease: false
78
120
  version_requirements: !ruby/object:Gem::Requirement
79
121
  requirements:
80
122
  - - "~>"
81
123
  - !ruby/object:Gem::Version
82
- version: '10.0'
124
+ version: '13.0'
83
125
  - !ruby/object:Gem::Dependency
84
126
  name: rspec
85
127
  requirement: !ruby/object:Gem::Requirement
@@ -95,7 +137,7 @@ dependencies:
95
137
  - !ruby/object:Gem::Version
96
138
  version: '3.0'
97
139
  - !ruby/object:Gem::Dependency
98
- name: byebug
140
+ name: rubocop
99
141
  requirement: !ruby/object:Gem::Requirement
100
142
  requirements:
101
143
  - - ">="
@@ -116,15 +158,20 @@ executables:
116
158
  extensions: []
117
159
  extra_rdoc_files: []
118
160
  files:
161
+ - ".github/workflows/ruby.yml"
119
162
  - ".gitignore"
120
163
  - ".rspec"
164
+ - ".rubocop.yml"
165
+ - ".rubocop_todo.yml"
121
166
  - ".travis.yml"
167
+ - CHANGELOG.md
122
168
  - Dockerfile
123
169
  - Gemfile
124
170
  - Gemfile.lock
125
171
  - LICENSE.txt
126
172
  - README.md
127
173
  - Rakefile
174
+ - Vertofile
128
175
  - bin/console
129
176
  - bin/setup
130
177
  - djin.gemspec
@@ -134,12 +181,17 @@ files:
134
181
  - exe/djin
135
182
  - lib/djin.rb
136
183
  - lib/djin/cli.rb
184
+ - lib/djin/config_loader.rb
137
185
  - lib/djin/entities/task.rb
138
186
  - lib/djin/entities/types.rb
139
187
  - lib/djin/executor.rb
140
- - lib/djin/extensions/custom_predicates.rb
141
188
  - lib/djin/extensions/hash_extensions.rb
142
189
  - lib/djin/interpreter.rb
190
+ - lib/djin/interpreter/base_command_builder.rb
191
+ - lib/djin/interpreter/docker_command_builder.rb
192
+ - lib/djin/interpreter/docker_compose_command_builder.rb
193
+ - lib/djin/interpreter/local_command_builder.rb
194
+ - lib/djin/repositories/task_repository.rb
143
195
  - lib/djin/task_contract.rb
144
196
  - lib/djin/version.rb
145
197
  homepage: https://github.com/catks/djin