djin 0.6.0 → 0.10.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 +8 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +8 -7
- data/README.md +125 -14
- data/Vertofile +7 -4
- data/djin.gemspec +1 -0
- data/djin.yml +5 -1
- 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/lib/djin.rb +21 -5
- data/lib/djin/cli.rb +12 -2
- data/lib/djin/config_loader.rb +82 -28
- data/lib/djin/entities/file_config.rb +31 -0
- data/lib/djin/entities/task.rb +3 -5
- data/lib/djin/extensions/hash_extensions.rb +14 -0
- data/lib/djin/extensions/object_extensions.rb +24 -0
- data/lib/djin/interpreter.rb +17 -4
- data/lib/djin/interpreter/base_command_builder.rb +1 -0
- data/lib/djin/memory_cache.rb +17 -0
- data/lib/djin/root_cli_parser.rb +42 -0
- data/lib/djin/task_contract.rb +1 -0
- data/lib/djin/version.rb +1 -1
- metadata +25 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5e44393cb2f47b9b3a68d2ce59ae997e5e1d6b252e68778293b5e62a7600374b
|
|
4
|
+
data.tar.gz: 5c02ed7dc956357e31b07c6ade84c5f660cb26469f7434ea0128b42f0ebec74f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1d8d9dbd993757586e35679c12e1d03b98c940e5bca58e6ab2b3b8955c84c78b2fad6ae2053a0430b85aa580217a8540b3196ab3489c0ae76c4426e712142822
|
|
7
|
+
data.tar.gz: be25638d743e46c62a452891298003d3dd93905ea38b6bbe51420d44549ba001785f7b9a631cc4e4b83c61ffa541688420df9bd9339023b1cb86747ad2ae87c4
|
data/.github/workflows/ruby.yml
CHANGED
|
@@ -14,10 +14,12 @@ jobs:
|
|
|
14
14
|
- uses: actions/setup-ruby@v1
|
|
15
15
|
with:
|
|
16
16
|
ruby-version: ${{ matrix.ruby }}
|
|
17
|
-
-
|
|
17
|
+
- name: Install Gems
|
|
18
|
+
run: |
|
|
18
19
|
gem install bundler
|
|
19
20
|
bundle install --jobs 4 --retry 3
|
|
20
|
-
|
|
21
|
+
- name: Run tests
|
|
22
|
+
run: bundle exec rake
|
|
21
23
|
|
|
22
24
|
lint:
|
|
23
25
|
runs-on: ubuntu-16.04
|
|
@@ -27,8 +29,10 @@ jobs:
|
|
|
27
29
|
- uses: actions/setup-ruby@v1
|
|
28
30
|
with:
|
|
29
31
|
ruby-version: '2.6'
|
|
30
|
-
-
|
|
32
|
+
- name: Install Gems
|
|
33
|
+
run: |
|
|
31
34
|
gem install bundler
|
|
32
35
|
bundle install --jobs 4 --retry 3
|
|
33
|
-
|
|
36
|
+
- name: Rubocop
|
|
37
|
+
run: bundle exec rubocop
|
|
34
38
|
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## 0.10.0 - 08/10/2020
|
|
2
|
+
* [FEATURE] -f command option
|
|
3
|
+
|
|
4
|
+
## 0.9.0 - 17/09/2020
|
|
5
|
+
* [FEATURE] Include Option
|
|
6
|
+
|
|
7
|
+
## 0.8.0 - 31/08/2020
|
|
8
|
+
* [FEATURE] Adds aliases option
|
|
9
|
+
|
|
10
|
+
## 0.7.0 - 20/08/2020
|
|
11
|
+
* [FEATURE] Adds description option
|
|
12
|
+
|
|
13
|
+
## 0.6.1 - 11/08/2020
|
|
14
|
+
* [TECH] Better Error Handling
|
|
15
|
+
|
|
1
16
|
## 0.6.0 - 22/07/2020
|
|
2
17
|
* [FEATURE] Djin Variables
|
|
3
18
|
|
data/Gemfile.lock
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
djin (0.
|
|
4
|
+
djin (0.10.0)
|
|
5
5
|
dry-cli (~> 0.6.0)
|
|
6
|
+
dry-equalizer (~> 0.3.0)
|
|
6
7
|
dry-struct (~> 1.3.0)
|
|
7
8
|
dry-validation (~> 1.5.1)
|
|
8
9
|
mustache (~> 1.1.1)
|
|
@@ -13,7 +14,7 @@ GEM
|
|
|
13
14
|
specs:
|
|
14
15
|
ast (2.4.1)
|
|
15
16
|
byebug (11.1.1)
|
|
16
|
-
concurrent-ruby (1.1.
|
|
17
|
+
concurrent-ruby (1.1.7)
|
|
17
18
|
diff-lcs (1.3)
|
|
18
19
|
dry-cli (0.6.0)
|
|
19
20
|
concurrent-ruby (~> 1.0)
|
|
@@ -28,12 +29,12 @@ GEM
|
|
|
28
29
|
concurrent-ruby (~> 1.0)
|
|
29
30
|
dry-equalizer (0.3.0)
|
|
30
31
|
dry-inflector (0.2.0)
|
|
31
|
-
dry-initializer (3.0.
|
|
32
|
-
dry-logic (1.0.
|
|
32
|
+
dry-initializer (3.0.4)
|
|
33
|
+
dry-logic (1.0.8)
|
|
33
34
|
concurrent-ruby (~> 1.0)
|
|
34
35
|
dry-core (~> 0.2)
|
|
35
36
|
dry-equalizer (~> 0.2)
|
|
36
|
-
dry-schema (1.5.
|
|
37
|
+
dry-schema (1.5.5)
|
|
37
38
|
concurrent-ruby (~> 1.0)
|
|
38
39
|
dry-configurable (~> 0.8, >= 0.8.3)
|
|
39
40
|
dry-core (~> 0.4)
|
|
@@ -53,13 +54,13 @@ GEM
|
|
|
53
54
|
dry-equalizer (~> 0.3)
|
|
54
55
|
dry-inflector (~> 0.1, >= 0.1.2)
|
|
55
56
|
dry-logic (~> 1.0, >= 1.0.2)
|
|
56
|
-
dry-validation (1.5.
|
|
57
|
+
dry-validation (1.5.6)
|
|
57
58
|
concurrent-ruby (~> 1.0)
|
|
58
59
|
dry-container (~> 0.7, >= 0.7.1)
|
|
59
60
|
dry-core (~> 0.4)
|
|
60
61
|
dry-equalizer (~> 0.2)
|
|
61
62
|
dry-initializer (~> 3.0)
|
|
62
|
-
dry-schema (~> 1.5)
|
|
63
|
+
dry-schema (~> 1.5, >= 1.5.2)
|
|
63
64
|
ice_nine (0.11.2)
|
|
64
65
|
mustache (1.1.1)
|
|
65
66
|
parallel (1.19.2)
|
data/README.md
CHANGED
|
@@ -26,7 +26,7 @@ If you use Rbenv you can install djin only once and create a alias in your .basr
|
|
|
26
26
|
To use djin first you need to create a djin.yml file:
|
|
27
27
|
|
|
28
28
|
```yaml
|
|
29
|
-
djin_version: '0.
|
|
29
|
+
djin_version: '0.10.0'
|
|
30
30
|
|
|
31
31
|
tasks:
|
|
32
32
|
# With a docker image
|
|
@@ -40,18 +40,20 @@ tasks:
|
|
|
40
40
|
|
|
41
41
|
# Using a docker-compose service
|
|
42
42
|
test:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
docker-compose:
|
|
44
|
+
service: app
|
|
45
|
+
run:
|
|
46
|
+
commands: rspec
|
|
47
|
+
options: "--rm"
|
|
48
|
+
aliases: # Optional Array of strings
|
|
49
|
+
- rspec
|
|
48
50
|
```
|
|
49
51
|
|
|
50
52
|
You can also set task dependencies with depends_on option:
|
|
51
53
|
|
|
52
54
|
|
|
53
55
|
```yaml
|
|
54
|
-
djin_version: '0.
|
|
56
|
+
djin_version: '0.10.0'
|
|
55
57
|
|
|
56
58
|
_default_run_options: &default_run_options
|
|
57
59
|
options: "--rm"
|
|
@@ -80,7 +82,7 @@ tasks:
|
|
|
80
82
|
Or mix local commands and docker/docker-compose commands:
|
|
81
83
|
|
|
82
84
|
```yaml
|
|
83
|
-
djin_version: '0.
|
|
85
|
+
djin_version: '0.10.0'
|
|
84
86
|
|
|
85
87
|
_default_run_options: &default_run_options
|
|
86
88
|
options: "--rm"
|
|
@@ -119,7 +121,7 @@ After that you can run `djin {{task_name}}`, like `djin script` or `djin test`
|
|
|
119
121
|
You can also use environment variables using the '{{YOUR_ENV_HERE}}' syntax, like so:
|
|
120
122
|
|
|
121
123
|
```yaml
|
|
122
|
-
djin_version: '0.
|
|
124
|
+
djin_version: '0.10.0'
|
|
123
125
|
|
|
124
126
|
_default_run_options: &default_run_options
|
|
125
127
|
options: "--rm"
|
|
@@ -136,7 +138,7 @@ tasks:
|
|
|
136
138
|
|
|
137
139
|
Or define some variables to use in multiple locations
|
|
138
140
|
```yaml
|
|
139
|
-
djin_version: '0.
|
|
141
|
+
djin_version: '0.10.0'
|
|
140
142
|
|
|
141
143
|
_default_run_options: &default_run_options
|
|
142
144
|
options: "--rm"
|
|
@@ -160,7 +162,7 @@ tasks:
|
|
|
160
162
|
It's also possible to pass custom arguments to the command, which means is possible to make a djin task act like the command itself:
|
|
161
163
|
|
|
162
164
|
```yaml
|
|
163
|
-
djin_version: '0.
|
|
165
|
+
djin_version: '0.10.0'
|
|
164
166
|
|
|
165
167
|
_default_run_options: &default_run_options
|
|
166
168
|
options: "--rm"
|
|
@@ -172,12 +174,117 @@ tasks:
|
|
|
172
174
|
run:
|
|
173
175
|
commands: rubocop {{args}}
|
|
174
176
|
<<: *default_run_options
|
|
177
|
+
aliases:
|
|
178
|
+
- lint
|
|
175
179
|
|
|
176
180
|
```
|
|
177
181
|
|
|
178
182
|
With that you can pass custom args after `--`, eg: `djin rubocop -- --parallel`, which wil make djin runs `rubocop --parallel` inside the service `app`.
|
|
179
183
|
|
|
180
|
-
Under the hood djin uses [Mustache](https://mustache.github.io/), so you can use other features like conditionals: `{{#IS_ENABLE}} Enabled {{/IS_ENABLE}}` (for args use the `args?`, eg: `{{#args?} {{args}} --and-other-thing{{/args?}}`), to see more more options you can access this [Link](https://mustache.github.io/mustache.5.html)
|
|
184
|
+
Under the hood djin uses [Mustache](https://mustache.github.io/), so you can use other features like conditionals: `{{#IS_ENABLE}} Enabled {{/IS_ENABLE}}` (for args use the `args?`, eg: `{{#args?}} {{args}} --and-other-thing{{/args?}}`), to see more more options you can access this [Link](https://mustache.github.io/mustache.5.html)
|
|
185
|
+
|
|
186
|
+
### Reusing tasks
|
|
187
|
+
|
|
188
|
+
If you have multiple tasks with similar behaviour and with small differences you can use the `include` keyword, so this:
|
|
189
|
+
|
|
190
|
+
```yaml
|
|
191
|
+
djin_version: '0.10.0'
|
|
192
|
+
|
|
193
|
+
tasks:
|
|
194
|
+
"host1:ssh":
|
|
195
|
+
local:
|
|
196
|
+
run:
|
|
197
|
+
- ssh my_user@host1.com.br
|
|
198
|
+
|
|
199
|
+
"host1:restart":
|
|
200
|
+
local:
|
|
201
|
+
run:
|
|
202
|
+
- ssh -t my_user@host1.com.br restart
|
|
203
|
+
|
|
204
|
+
"host1:logs":
|
|
205
|
+
local:
|
|
206
|
+
run:
|
|
207
|
+
- ssh -t my_user@host1.com.br tail -f /var/log/my_log
|
|
208
|
+
|
|
209
|
+
"host2:ssh":
|
|
210
|
+
local:
|
|
211
|
+
run:
|
|
212
|
+
- ssh my_user@host2.com.br
|
|
213
|
+
|
|
214
|
+
"host2:restart":
|
|
215
|
+
local:
|
|
216
|
+
run:
|
|
217
|
+
- ssh -t my_user@host2.com.br restart
|
|
218
|
+
|
|
219
|
+
"host2:logs":
|
|
220
|
+
local:
|
|
221
|
+
run:
|
|
222
|
+
- ssh -t my_user@host2.com.br tail -f /var/log/my_file
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
can become this:
|
|
227
|
+
|
|
228
|
+
```yaml
|
|
229
|
+
# djin.yml
|
|
230
|
+
djin_version: '0.10.0'
|
|
231
|
+
|
|
232
|
+
include:
|
|
233
|
+
- file: '.djin/server_tasks.yml'
|
|
234
|
+
context:
|
|
235
|
+
variables:
|
|
236
|
+
namespace: host1
|
|
237
|
+
host: host1.com
|
|
238
|
+
ssh_user: my_user
|
|
239
|
+
|
|
240
|
+
- file: '.djin/server_tasks.yml'
|
|
241
|
+
context:
|
|
242
|
+
variables:
|
|
243
|
+
namespace: host2
|
|
244
|
+
host: host2.com
|
|
245
|
+
ssh_user: my_user
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
```yaml
|
|
251
|
+
# .djin/server_tasks.yml
|
|
252
|
+
djin_version: '0.10.0'
|
|
253
|
+
|
|
254
|
+
tasks:
|
|
255
|
+
"{{namespace}}:ssh":
|
|
256
|
+
local:
|
|
257
|
+
run:
|
|
258
|
+
- ssh {{ssh_user}}@{{host}}
|
|
259
|
+
|
|
260
|
+
"{{namespace}}:restart":
|
|
261
|
+
local:
|
|
262
|
+
run:
|
|
263
|
+
- ssh -t {{ssh_user}}@{{host}} restart
|
|
264
|
+
|
|
265
|
+
"{{namespace}}:logs":
|
|
266
|
+
local:
|
|
267
|
+
run:
|
|
268
|
+
- ssh -t {{ssh_user}}@{{host}} tail -f /var/log/my_log
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Loading custom files
|
|
272
|
+
|
|
273
|
+
You can also specify a file to be read by djin with `-f`, eg:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
djin -f my_file.yml # Returns the help for all tasks in my_file
|
|
277
|
+
djin -f my_file.yml build # Execute the build task defined in my_file.yml
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
You can also specify multiple files to join tasks between files:
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# Mix the tasks
|
|
284
|
+
djin -f my_file.yml -f my_file2.yml # Returns the help for all tasks in my_file
|
|
285
|
+
djin -f my_file.yml -f my_file2.yml build # Execute the build task defined in my_file.yml or my_file2.yml
|
|
286
|
+
```
|
|
287
|
+
|
|
181
288
|
|
|
182
289
|
## Development
|
|
183
290
|
|
|
@@ -185,9 +292,13 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
|
185
292
|
|
|
186
293
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, run `djin release -- {{increment_option}}` (where {{incremment_option}} can be `--patch`, `--minor` or `major`), which will change version, update the CHANGELOG.md, create a new commit, create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
187
294
|
|
|
188
|
-
## TODO:
|
|
189
295
|
|
|
190
|
-
|
|
296
|
+
## TODO
|
|
297
|
+
|
|
298
|
+
1. Enable multiple -f options to merge configuration between files
|
|
299
|
+
2. Option to export tasks to Makefile
|
|
300
|
+
3. djin-export docker image to create and sync makefiles
|
|
301
|
+
4. include key option to add tasks in git repositories files (maybe with a local cache)
|
|
191
302
|
|
|
192
303
|
## Contributing
|
|
193
304
|
|
data/Vertofile
CHANGED
|
@@ -28,12 +28,15 @@ context(branch('master')) {
|
|
|
28
28
|
file('CHANGELOG.md').prepend(version_changes)
|
|
29
29
|
git!('add CHANGELOG.md')
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
files_to_change_version_once = %w[lib/djin/version.rb djin.yml] + Dir['examples/**/*.yml'] + Dir['spec/support/fixtures/**/*.yml']
|
|
32
|
+
|
|
33
|
+
files_to_change_version_once.each do |filename|
|
|
34
|
+
file(filename).replace(latest_version.to_s, new_version.to_s)
|
|
35
|
+
end
|
|
36
|
+
|
|
34
37
|
file('README.md').replace_all(latest_version.to_s, new_version.to_s)
|
|
35
38
|
|
|
36
|
-
git!(
|
|
39
|
+
git!("add #{files_to_change_version_once.join(' ')} README.md")
|
|
37
40
|
|
|
38
41
|
sh!('bundle install')
|
|
39
42
|
sh!('rake install')
|
data/djin.gemspec
CHANGED
|
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
|
|
|
28
28
|
spec.require_paths = ['lib']
|
|
29
29
|
|
|
30
30
|
spec.add_dependency 'dry-cli', '~> 0.6.0'
|
|
31
|
+
spec.add_dependency 'dry-equalizer', '~> 0.3.0'
|
|
31
32
|
spec.add_dependency 'dry-struct', '~> 1.3.0'
|
|
32
33
|
spec.add_dependency 'dry-validation', '~> 1.5.1'
|
|
33
34
|
spec.add_dependency 'mustache', '~> 1.1.1'
|
data/djin.yml
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
djin_version: '0.
|
|
1
|
+
djin_version: '0.10.0'
|
|
2
2
|
|
|
3
3
|
_default_run_options: &default_run_options
|
|
4
4
|
options: "--rm --entrypoint=''"
|
|
5
5
|
|
|
6
6
|
tasks:
|
|
7
7
|
test:
|
|
8
|
+
description: Runs Specs
|
|
8
9
|
docker-compose:
|
|
9
10
|
service: app
|
|
10
11
|
run:
|
|
11
12
|
commands: "cd /usr/src/djin && rspec {{args}}"
|
|
12
13
|
<<: *default_run_options
|
|
14
|
+
aliases:
|
|
15
|
+
- rspec
|
|
13
16
|
|
|
14
17
|
sh:
|
|
18
|
+
description: Enter app service shell
|
|
15
19
|
docker-compose:
|
|
16
20
|
service: app
|
|
17
21
|
run:
|
data/examples/djin.yml
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
---
|
|
2
|
-
djin_version: '0.
|
|
2
|
+
djin_version: '0.10.0'
|
|
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.10.0'
|
|
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,9 +8,12 @@ require 'dry-validation'
|
|
|
8
8
|
require 'vseries'
|
|
9
9
|
require 'dry/cli'
|
|
10
10
|
require 'mustache'
|
|
11
|
+
require 'optparse'
|
|
11
12
|
require 'djin/extensions/hash_extensions'
|
|
13
|
+
require 'djin/extensions/object_extensions'
|
|
12
14
|
require 'djin/entities/types'
|
|
13
15
|
require 'djin/entities/task'
|
|
16
|
+
require 'djin/entities/file_config'
|
|
14
17
|
require 'djin/interpreter/base_command_builder'
|
|
15
18
|
require 'djin/interpreter/docker_command_builder'
|
|
16
19
|
require 'djin/interpreter/docker_compose_command_builder'
|
|
@@ -18,25 +21,30 @@ require 'djin/interpreter/local_command_builder'
|
|
|
18
21
|
require 'djin/interpreter'
|
|
19
22
|
require 'djin/config_loader'
|
|
20
23
|
require 'djin/executor'
|
|
24
|
+
require 'djin/root_cli_parser'
|
|
21
25
|
require 'djin/cli'
|
|
22
26
|
require 'djin/task_contract'
|
|
23
27
|
require 'djin/repositories/task_repository'
|
|
28
|
+
require 'djin/memory_cache'
|
|
24
29
|
|
|
25
30
|
module Djin
|
|
26
31
|
class Error < StandardError; end
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
abort 'Error: djin.yml not found' unless path.exist?
|
|
33
|
+
using Djin::ObjectExtensions
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
def self.load_tasks!(*file_paths)
|
|
36
|
+
files = file_paths.presence || RootCliParser.parse![:files] || ['djin.yml']
|
|
37
|
+
|
|
38
|
+
file_config = ConfigLoader.load_files!(*files)
|
|
32
39
|
|
|
33
40
|
# TODO: Make all tasks be under 'tasks' key, passing only the tasks here
|
|
34
|
-
tasks = Interpreter.load!(
|
|
41
|
+
tasks = Interpreter.load!(file_config)
|
|
35
42
|
|
|
36
43
|
@task_repository = TaskRepository.new(tasks)
|
|
37
44
|
CLI.load_tasks!(tasks)
|
|
38
45
|
rescue Djin::Interpreter::InvalidConfigurationError => e
|
|
39
|
-
|
|
46
|
+
error_name = e.class.name.split('::').last
|
|
47
|
+
abort("[#{error_name}] #{e.message}")
|
|
40
48
|
end
|
|
41
49
|
|
|
42
50
|
def self.tasks
|
|
@@ -46,4 +54,12 @@ module Djin
|
|
|
46
54
|
def self.task_repository
|
|
47
55
|
@task_repository ||= TaskRepository.new
|
|
48
56
|
end
|
|
57
|
+
|
|
58
|
+
def self.cache
|
|
59
|
+
@cache ||= MemoryCache.new
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.root_path
|
|
63
|
+
Pathname.new File.expand_path(File.dirname(__FILE__) + '/..')
|
|
64
|
+
end
|
|
49
65
|
end
|
data/lib/djin/cli.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Djin
|
|
|
7
7
|
def self.load_tasks!(tasks)
|
|
8
8
|
tasks.each do |task|
|
|
9
9
|
command = Class.new(Dry::CLI::Command) do
|
|
10
|
-
desc
|
|
10
|
+
desc task.description
|
|
11
11
|
|
|
12
12
|
define_method(:task) { task }
|
|
13
13
|
|
|
@@ -16,7 +16,7 @@ module Djin
|
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
register
|
|
19
|
+
register(task.name, command, aliases: task.aliases)
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
@@ -28,6 +28,16 @@ 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
|
+
register '-f', File, aliases: ['--file']
|
|
31
41
|
register '--version', Version, aliases: ['-v']
|
|
32
42
|
end
|
|
33
43
|
end
|
data/lib/djin/config_loader.rb
CHANGED
|
@@ -6,39 +6,46 @@ module Djin
|
|
|
6
6
|
# a TaskLoader
|
|
7
7
|
class ConfigLoader
|
|
8
8
|
using Djin::HashExtensions
|
|
9
|
-
RESERVED_WORDS = %w[djin_version variables tasks].freeze
|
|
9
|
+
RESERVED_WORDS = %w[djin_version variables tasks include].freeze
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
# CHange Base Error
|
|
12
|
+
FileNotFoundError = Class.new(Interpreter::InvalidConfigurationError)
|
|
13
|
+
|
|
14
|
+
def self.load_files!(*files, runtime_config: {}, base_directory: '.')
|
|
15
|
+
files.map do |file_path|
|
|
16
|
+
ConfigLoader.load!(file_path, runtime_config: runtime_config, base_directory: base_directory)
|
|
17
|
+
end&.reduce(:deep_merge)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.load!(template_file_path, runtime_config: {}, base_directory: '.')
|
|
21
|
+
new(template_file_path, runtime_config: runtime_config, base_directory: base_directory).load!
|
|
13
22
|
end
|
|
14
23
|
|
|
15
|
-
def initialize(
|
|
16
|
-
@
|
|
24
|
+
def initialize(template_file_path, runtime_config: {}, base_directory: '.')
|
|
25
|
+
@base_directory = Pathname.new(base_directory)
|
|
26
|
+
@template_file = @base_directory.join(template_file_path)
|
|
27
|
+
|
|
28
|
+
raise FileNotFoundError, "File '#{@template_file}' not found" unless @template_file.exist?
|
|
29
|
+
|
|
30
|
+
@template_file_content = Djin.cache.fetch(@template_file.realpath.to_s) { @template_file.read }
|
|
31
|
+
@runtime_config = runtime_config
|
|
17
32
|
end
|
|
18
33
|
|
|
19
34
|
def load!
|
|
20
35
|
validate_version!
|
|
21
36
|
|
|
22
|
-
|
|
23
|
-
tasks
|
|
37
|
+
file_config
|
|
24
38
|
end
|
|
25
39
|
|
|
26
40
|
private
|
|
27
41
|
|
|
28
|
-
def
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
rendered_yaml = Mustache.render(@template_file,
|
|
37
|
-
args: args.join(' '),
|
|
38
|
-
args?: args.any?,
|
|
39
|
-
**locals)
|
|
40
|
-
yaml_load(rendered_yaml)
|
|
41
|
-
end
|
|
42
|
+
def file_config
|
|
43
|
+
FileConfig.new(
|
|
44
|
+
djin_version: version,
|
|
45
|
+
variables: variables,
|
|
46
|
+
tasks: tasks,
|
|
47
|
+
raw_tasks: raw_tasks
|
|
48
|
+
)
|
|
42
49
|
end
|
|
43
50
|
|
|
44
51
|
def version
|
|
@@ -47,11 +54,15 @@ module Djin
|
|
|
47
54
|
end
|
|
48
55
|
|
|
49
56
|
def variables
|
|
50
|
-
@variables ||= raw_djin_config['variables']&.symbolize_keys || {}
|
|
57
|
+
@variables ||= included_variables.merge(raw_djin_config['variables']&.symbolize_keys || {})
|
|
51
58
|
end
|
|
52
59
|
|
|
53
60
|
def tasks
|
|
54
|
-
rendered_djin_config['tasks'] || legacy_tasks
|
|
61
|
+
included_tasks.merge(rendered_djin_config['tasks'] || legacy_tasks)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def raw_tasks
|
|
65
|
+
included_raw_tasks.merge(raw_djin_config['tasks'] || legacy_raw_tasks)
|
|
55
66
|
end
|
|
56
67
|
|
|
57
68
|
def legacy_tasks
|
|
@@ -61,6 +72,35 @@ module Djin
|
|
|
61
72
|
rendered_djin_config.except(*RESERVED_WORDS).reject { |task| task.start_with?('_') }
|
|
62
73
|
end
|
|
63
74
|
|
|
75
|
+
def legacy_raw_tasks
|
|
76
|
+
raw_djin_config.except(*RESERVED_WORDS).reject { |task| task.start_with?('_') }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def included_variables
|
|
80
|
+
return {} unless included_config
|
|
81
|
+
|
|
82
|
+
included_config.variables
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def included_tasks
|
|
86
|
+
return {} unless included_config
|
|
87
|
+
|
|
88
|
+
included_config.tasks
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def included_raw_tasks
|
|
92
|
+
return {} unless included_config
|
|
93
|
+
|
|
94
|
+
included_config.raw_tasks
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def included_config
|
|
98
|
+
@included_config ||= raw_djin_config['include']&.map do |tasks_reference|
|
|
99
|
+
ConfigLoader.load!(tasks_reference['file'], base_directory: @template_file.dirname,
|
|
100
|
+
runtime_config: tasks_reference['context'] || {})
|
|
101
|
+
end&.reduce(:deep_merge)
|
|
102
|
+
end
|
|
103
|
+
|
|
64
104
|
def args
|
|
65
105
|
index = ARGV.index('--')
|
|
66
106
|
|
|
@@ -73,18 +113,32 @@ module Djin
|
|
|
73
113
|
@env ||= ENV.to_h.symbolize_keys
|
|
74
114
|
end
|
|
75
115
|
|
|
76
|
-
def
|
|
77
|
-
|
|
116
|
+
def raw_djin_config
|
|
117
|
+
@raw_djin_config ||= yaml_load(@template_file_content).deep_merge(@runtime_config)
|
|
118
|
+
rescue Psych::SyntaxError => e
|
|
119
|
+
raise Interpreter::InvalidConfigFileError, "File: #{@template_file.realpath}\n #{e.message}"
|
|
78
120
|
end
|
|
79
121
|
|
|
80
|
-
def
|
|
81
|
-
|
|
122
|
+
def rendered_djin_config
|
|
123
|
+
@rendered_djin_config ||= begin
|
|
124
|
+
locals = env.merge(variables)
|
|
125
|
+
|
|
126
|
+
rendered_yaml = Mustache.render(@template_file_content,
|
|
127
|
+
args: args.join(' '),
|
|
128
|
+
args?: args.any?,
|
|
129
|
+
**locals)
|
|
130
|
+
yaml_load(rendered_yaml).merge(@runtime_config)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def yaml_load(text)
|
|
135
|
+
YAML.safe_load(text, [], [], true)
|
|
82
136
|
end
|
|
83
137
|
|
|
84
138
|
def validate_version!
|
|
85
139
|
raise Interpreter::MissingVersionError, 'Missing djin_version' unless version
|
|
86
140
|
|
|
87
|
-
return if version_supported?
|
|
141
|
+
return if file_config.version_supported?
|
|
88
142
|
|
|
89
143
|
raise Interpreter::VersionNotSupportedError, "Version #{version} is not supported, use #{Djin::VERSION} or higher"
|
|
90
144
|
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Djin
|
|
4
|
+
class FileConfig < Dry::Struct
|
|
5
|
+
using HashExtensions
|
|
6
|
+
|
|
7
|
+
attribute :djin_version, Types::String
|
|
8
|
+
attribute :variables, Types::Hash.optional.default({}.freeze)
|
|
9
|
+
attribute :tasks, Types::Hash
|
|
10
|
+
attribute :raw_tasks, Types::Hash
|
|
11
|
+
# TODO: Add env and args
|
|
12
|
+
|
|
13
|
+
include Dry::Equalizer(:djin_version, :variables, :tasks, :raw_tasks)
|
|
14
|
+
|
|
15
|
+
def version_supported?
|
|
16
|
+
Vseries::SemanticVersion.new(Djin::VERSION) >= Vseries::SemanticVersion.new(djin_version)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def merge(file_config)
|
|
20
|
+
merged_hash = to_h.merge(file_config.to_h)
|
|
21
|
+
|
|
22
|
+
FileConfig.new(merged_hash)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def deep_merge(file_config)
|
|
26
|
+
merged_hash = to_h.deep_merge(file_config.to_h)
|
|
27
|
+
|
|
28
|
+
FileConfig.new(merged_hash)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/djin/entities/task.rb
CHANGED
|
@@ -6,12 +6,10 @@ module Djin
|
|
|
6
6
|
attribute :description, Types::String.optional.default(nil)
|
|
7
7
|
attribute :build_command, Types::String.optional.default(nil)
|
|
8
8
|
attribute :command, Types::String.optional.default(nil)
|
|
9
|
+
attribute :raw_command, Types::String.optional.default(nil)
|
|
10
|
+
attribute :aliases, Types::Array.of(Types::String).optional.default([].freeze)
|
|
9
11
|
attribute :depends_on, Types::Array.of(Types::String).optional.default([].freeze)
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
name == other.name &&
|
|
13
|
-
command == other.command &&
|
|
14
|
-
build_command == other.build_command
|
|
15
|
-
end
|
|
13
|
+
include Dry::Equalizer(:name, :command, :build_command)
|
|
16
14
|
end
|
|
17
15
|
end
|
|
@@ -10,6 +10,20 @@ module Djin
|
|
|
10
10
|
def symbolize_keys
|
|
11
11
|
map { |key, value| [key.to_sym, value] }.to_h
|
|
12
12
|
end
|
|
13
|
+
|
|
14
|
+
def deep_merge(other_hash)
|
|
15
|
+
dup.deep_merge!(other_hash)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def deep_merge!(other_hash)
|
|
19
|
+
merge!(other_hash) do |_, this_val, other_val|
|
|
20
|
+
if this_val.is_a?(Hash) && other_val.is_a?(Hash)
|
|
21
|
+
this_val.deep_merge(other_val)
|
|
22
|
+
else
|
|
23
|
+
other_val
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
13
27
|
end
|
|
14
28
|
end
|
|
15
29
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Djin
|
|
4
|
+
module ObjectExtensions
|
|
5
|
+
refine Object do
|
|
6
|
+
def presence(default = nil)
|
|
7
|
+
present? ? self : default
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def present?
|
|
11
|
+
!blank?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def blank?
|
|
15
|
+
return true unless self
|
|
16
|
+
|
|
17
|
+
# TODO: Improve Validations
|
|
18
|
+
return empty? if respond_to?(:empty?)
|
|
19
|
+
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/djin/interpreter.rb
CHANGED
|
@@ -6,31 +6,44 @@ module Djin
|
|
|
6
6
|
|
|
7
7
|
# TODO: Move Errors to ConfigLoader
|
|
8
8
|
InvalidConfigurationError = Class.new(StandardError)
|
|
9
|
+
InvalidConfigFileError = Class.new(InvalidConfigurationError)
|
|
9
10
|
MissingVersionError = Class.new(InvalidConfigurationError)
|
|
10
11
|
VersionNotSupportedError = Class.new(InvalidConfigurationError)
|
|
11
12
|
InvalidSyntaxError = Class.new(InvalidConfigurationError)
|
|
12
13
|
|
|
13
14
|
class << self
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
# rubocop:disable Metrics/AbcSize
|
|
16
|
+
def load!(file_config)
|
|
17
|
+
# TODO: Move task validation to ConfigLoader and add variables/include validations
|
|
18
|
+
task_contract = TaskContract.new
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
result =
|
|
20
|
+
file_config.tasks.map do |task_name, options|
|
|
21
|
+
result = task_contract.call(options)
|
|
19
22
|
|
|
20
23
|
raise InvalidSyntaxError, { task_name.to_sym => result.errors.to_h } if result.failure?
|
|
21
24
|
|
|
22
25
|
command, build_command = build_commands(options, task_name: task_name)
|
|
23
26
|
|
|
27
|
+
# FIXME(1): Handle dynamic named tasks, eg: {{namespace}}unit and remove condition
|
|
28
|
+
if file_config.raw_tasks[task_name]
|
|
29
|
+
raw_command, = build_commands(file_config.raw_tasks[task_name], task_name: task_name)
|
|
30
|
+
end
|
|
31
|
+
|
|
24
32
|
task_params = {
|
|
25
33
|
name: task_name,
|
|
26
34
|
build_command: build_command,
|
|
35
|
+
# TODO: Remove `|| command` after FIXME(1)
|
|
36
|
+
description: options['description'] || "Runs: #{raw_command || command}",
|
|
27
37
|
command: command,
|
|
38
|
+
raw_command: raw_command,
|
|
39
|
+
aliases: options['aliases'],
|
|
28
40
|
depends_on: options['depends_on']
|
|
29
41
|
}.compact
|
|
30
42
|
|
|
31
43
|
Djin::Task.new(**task_params)
|
|
32
44
|
end
|
|
33
45
|
end
|
|
46
|
+
# rubocop:enable Metrics/AbcSize
|
|
34
47
|
|
|
35
48
|
private
|
|
36
49
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Djin
|
|
4
|
+
class MemoryCache
|
|
5
|
+
def initialize(hash_store = {})
|
|
6
|
+
@hash_store = hash_store
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def fetch(key)
|
|
10
|
+
@hash_store[key] || @hash_store[key] = yield
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def clear
|
|
14
|
+
@hash_store = {}
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Djin
|
|
4
|
+
## This class is responsible to handle options that must be evaluated
|
|
5
|
+
# before the load of tasks in djin file(eg: djin.yml)
|
|
6
|
+
class RootCliParser
|
|
7
|
+
class << self
|
|
8
|
+
def parse!(args = ARGV)
|
|
9
|
+
options = {}
|
|
10
|
+
|
|
11
|
+
# TODO: Find a better way to handle -f/--file option,
|
|
12
|
+
# throw, catch and delete in ARGV are necessary
|
|
13
|
+
# to only remove the -f/--file option
|
|
14
|
+
# and bypass everything else to Dry::CLI
|
|
15
|
+
catch(:root_cli_exit) do
|
|
16
|
+
OptionParser.new do |opts|
|
|
17
|
+
opts.on('-f FILE', '--file FILE') do |v|
|
|
18
|
+
options[:files] ||= []
|
|
19
|
+
options[:files] << v
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
opts.on('-h', '--help') do
|
|
23
|
+
throw :root_cli_exit
|
|
24
|
+
end
|
|
25
|
+
end.parse(args)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
remove_file_args!(args)
|
|
29
|
+
options
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def remove_file_args!(args)
|
|
33
|
+
file_option = ['-f', '--file']
|
|
34
|
+
args_indexes_to_remove = args.each_with_index.map do |value, index|
|
|
35
|
+
index if (file_option.include?(args[index - 1]) && index.positive?) || file_option.include?(value)
|
|
36
|
+
end.compact
|
|
37
|
+
|
|
38
|
+
args_indexes_to_remove.reverse.each { |index| args.delete_at(index) }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/djin/task_contract.rb
CHANGED
data/lib/djin/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: djin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.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-10-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: dry-cli
|
|
@@ -24,6 +24,20 @@ dependencies:
|
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
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
|
|
27
41
|
- !ruby/object:Gem::Dependency
|
|
28
42
|
name: dry-struct
|
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -178,20 +192,27 @@ files:
|
|
|
178
192
|
- djin.yml
|
|
179
193
|
- docker-compose.yml
|
|
180
194
|
- examples/djin.yml
|
|
195
|
+
- examples/djin_lib/test.yml
|
|
196
|
+
- examples/local_tasks/.djin/server_tasks.yml
|
|
197
|
+
- examples/local_tasks/djin.yml
|
|
181
198
|
- exe/djin
|
|
182
199
|
- lib/djin.rb
|
|
183
200
|
- lib/djin/cli.rb
|
|
184
201
|
- lib/djin/config_loader.rb
|
|
202
|
+
- lib/djin/entities/file_config.rb
|
|
185
203
|
- lib/djin/entities/task.rb
|
|
186
204
|
- lib/djin/entities/types.rb
|
|
187
205
|
- lib/djin/executor.rb
|
|
188
206
|
- lib/djin/extensions/hash_extensions.rb
|
|
207
|
+
- lib/djin/extensions/object_extensions.rb
|
|
189
208
|
- lib/djin/interpreter.rb
|
|
190
209
|
- lib/djin/interpreter/base_command_builder.rb
|
|
191
210
|
- lib/djin/interpreter/docker_command_builder.rb
|
|
192
211
|
- lib/djin/interpreter/docker_compose_command_builder.rb
|
|
193
212
|
- lib/djin/interpreter/local_command_builder.rb
|
|
213
|
+
- lib/djin/memory_cache.rb
|
|
194
214
|
- lib/djin/repositories/task_repository.rb
|
|
215
|
+
- lib/djin/root_cli_parser.rb
|
|
195
216
|
- lib/djin/task_contract.rb
|
|
196
217
|
- lib/djin/version.rb
|
|
197
218
|
homepage: https://github.com/catks/djin
|
|
@@ -213,7 +234,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
213
234
|
- !ruby/object:Gem::Version
|
|
214
235
|
version: '0'
|
|
215
236
|
requirements: []
|
|
216
|
-
|
|
237
|
+
rubyforge_project:
|
|
238
|
+
rubygems_version: 2.7.6
|
|
217
239
|
signing_key:
|
|
218
240
|
specification_version: 4
|
|
219
241
|
summary: djin is a make-like utility for docker containers
|