djin 0.11.3 → 0.11.7
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 +3 -3
- data/.rubocop.yml +5 -1
- data/CHANGELOG.md +14 -0
- data/Dockerfile +6 -2
- data/Gemfile.lock +19 -14
- data/README.md +13 -14
- data/djin.gemspec +6 -1
- data/djin.yml +1 -1
- data/docker-entrypoint.sh +2 -0
- data/examples/djin.yml +1 -1
- data/examples/djin_lib/test.yml +1 -1
- data/examples/local_tasks/djin.yml +1 -1
- data/examples/remote_tasks/djin.yml +1 -1
- data/lib/djin/cli.rb +4 -0
- data/lib/djin/config_loader.rb +17 -29
- data/lib/djin/errors.rb +12 -0
- data/lib/djin/executor.rb +4 -4
- data/lib/djin/{include_resolver.rb → include_config_loader.rb} +26 -4
- data/lib/djin/include_contract.rb +39 -0
- data/lib/djin/interpreter.rb +1 -7
- data/lib/djin/version.rb +1 -1
- data/lib/djin.rb +4 -2
- data/wait-for-it.sh +183 -0
- metadata +79 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 334bacc0c5681d6f6f231afaaa65c8be71a6d8c9f6c0aa1d2c77a830328285df
|
4
|
+
data.tar.gz: 123947c969381b5bdca2e5a66635333f8f5f63ab771833cfccfbc8a1ee5d7efe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fab86e9ee5d886fc8e9717df718af42fe8694dc7bbcb0911699b987da94f3faecbdb29112af212152d3050b9a8919558a09af05afccc75ec89380556c38f7141
|
7
|
+
data.tar.gz: 22445b50834c0d054c5d1bc5caea641ab2f8361f9c0c7862773281e37be68269ad27743a25de4eb5277d77ae29a693e009ad19def31e138f2ad55eef93dd16f1
|
data/.github/workflows/ruby.yml
CHANGED
@@ -4,7 +4,7 @@ on: [push, workflow_dispatch]
|
|
4
4
|
|
5
5
|
jobs:
|
6
6
|
build:
|
7
|
-
runs-on: ubuntu-
|
7
|
+
runs-on: ubuntu-18.04
|
8
8
|
strategy:
|
9
9
|
matrix:
|
10
10
|
ruby: [ '2.5', '2.6', '2.7' ]
|
@@ -20,7 +20,7 @@ jobs:
|
|
20
20
|
|
21
21
|
- name: Build
|
22
22
|
run: |
|
23
|
-
docker-compose -p djin_ruby_${{ matrix.ruby }} build --build-arg
|
23
|
+
docker-compose -p djin_ruby_${{ matrix.ruby }} build --build-arg RUBY_VERSION=${{ matrix.ruby }} app
|
24
24
|
|
25
25
|
- name: Run tests
|
26
26
|
run: |
|
@@ -34,7 +34,7 @@ jobs:
|
|
34
34
|
docker-compose -p djin_ruby_${{ matrix.ruby }} run --rm app 'export GIT_BRANCH="${GITHUB_REF/refs\/heads\//}" && ./cc-test-reporter after-build -r ${{secrets.CC_TEST_REPORTER_ID}}'
|
35
35
|
|
36
36
|
lint:
|
37
|
-
runs-on: ubuntu-
|
37
|
+
runs-on: ubuntu-18.04
|
38
38
|
name: Lint
|
39
39
|
steps:
|
40
40
|
- uses: actions/checkout@v2
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## 0.11.7 - 27/10/2021
|
2
|
+
* [FIX] Djin Dependencies
|
3
|
+
* [TECH][FIX] Ruby Versions in CI
|
4
|
+
* [FIX] Version Error Message
|
5
|
+
|
6
|
+
## 0.11.6 - 26/02/2021
|
7
|
+
* [FIX] Enable ssh and file repositories in include option
|
8
|
+
|
9
|
+
## 0.11.5 - 23/02/2021
|
10
|
+
* [FIX] Aborting when dependent task fail
|
11
|
+
|
12
|
+
## 0.11.4 - 12/02/2021
|
13
|
+
* [PATCH] Include Config Validations
|
14
|
+
|
1
15
|
## 0.11.3 - 29/01/2021
|
2
16
|
* [FIX] --version, -v
|
3
17
|
|
data/Dockerfile
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
ARG RUBY_VERSION
|
2
|
-
FROM ruby:${RUBY_VERSION:-2.6
|
2
|
+
FROM ruby:${RUBY_VERSION:-2.6}-alpine3.12 AS builder
|
3
3
|
|
4
4
|
ENV BUILD_PACKAGES build-base git
|
5
|
+
ENV DEV_PACKAGES bash
|
5
6
|
|
6
7
|
RUN mkdir /bundle
|
7
8
|
|
@@ -20,6 +21,9 @@ RUN bundle install
|
|
20
21
|
|
21
22
|
FROM builder AS dev
|
22
23
|
|
24
|
+
RUN apk add $DEV_PACKAGES && \
|
25
|
+
rm -rf /var/cache/apk/*
|
26
|
+
|
23
27
|
WORKDIR /usr/src/djin
|
24
28
|
|
25
29
|
COPY . .
|
@@ -45,4 +49,4 @@ RUN rake install
|
|
45
49
|
|
46
50
|
WORKDIR /usr/src/project
|
47
51
|
|
48
|
-
ENTRYPOINT ["/usr/src/
|
52
|
+
ENTRYPOINT ["/usr/src/djin/docker-entrypoint.sh"]
|
data/Gemfile.lock
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
djin (0.11.
|
4
|
+
djin (0.11.7)
|
5
5
|
dry-cli (~> 0.6.0)
|
6
|
+
dry-configurable (~> 0.9.0)
|
7
|
+
dry-container (~> 0.7.0)
|
8
|
+
dry-core (~> 0.6.0)
|
6
9
|
dry-equalizer (~> 0.3.0)
|
10
|
+
dry-inflector (~> 0.1.0)
|
11
|
+
dry-schema (~> 1.6.0)
|
7
12
|
dry-struct (~> 1.3.0)
|
8
|
-
dry-validation (
|
13
|
+
dry-validation (= 1.5.1)
|
9
14
|
git (~> 1.8.1)
|
10
15
|
mustache (~> 1.1.1)
|
11
16
|
vseries (~> 0.1.0)
|
@@ -26,21 +31,21 @@ GEM
|
|
26
31
|
docile (1.3.2)
|
27
32
|
dry-cli (0.6.0)
|
28
33
|
concurrent-ruby (~> 1.0)
|
29
|
-
dry-configurable (0.
|
34
|
+
dry-configurable (0.9.0)
|
30
35
|
concurrent-ruby (~> 1.0)
|
31
|
-
dry-core (~> 0.
|
36
|
+
dry-core (~> 0.4, >= 0.4.7)
|
32
37
|
dry-container (0.7.2)
|
33
38
|
concurrent-ruby (~> 1.0)
|
34
39
|
dry-configurable (~> 0.1, >= 0.1.3)
|
35
|
-
dry-core (0.
|
40
|
+
dry-core (0.6.0)
|
36
41
|
concurrent-ruby (~> 1.0)
|
37
42
|
dry-equalizer (0.3.0)
|
38
|
-
dry-inflector (0.2
|
43
|
+
dry-inflector (0.1.2)
|
39
44
|
dry-initializer (3.0.4)
|
40
|
-
dry-logic (1.
|
45
|
+
dry-logic (1.2.0)
|
41
46
|
concurrent-ruby (~> 1.0)
|
42
47
|
dry-core (~> 0.5, >= 0.5)
|
43
|
-
dry-schema (1.6.
|
48
|
+
dry-schema (1.6.2)
|
44
49
|
concurrent-ruby (~> 1.0)
|
45
50
|
dry-configurable (~> 0.8, >= 0.8.3)
|
46
51
|
dry-core (~> 0.5, >= 0.5)
|
@@ -52,19 +57,19 @@ GEM
|
|
52
57
|
dry-equalizer (~> 0.3)
|
53
58
|
dry-types (~> 1.3)
|
54
59
|
ice_nine (~> 0.11)
|
55
|
-
dry-types (1.5.
|
60
|
+
dry-types (1.5.1)
|
56
61
|
concurrent-ruby (~> 1.0)
|
57
62
|
dry-container (~> 0.3)
|
58
63
|
dry-core (~> 0.5, >= 0.5)
|
59
64
|
dry-inflector (~> 0.1, >= 0.1.2)
|
60
65
|
dry-logic (~> 1.0, >= 1.0.2)
|
61
|
-
dry-validation (1.5.
|
66
|
+
dry-validation (1.5.1)
|
62
67
|
concurrent-ruby (~> 1.0)
|
63
68
|
dry-container (~> 0.7, >= 0.7.1)
|
64
69
|
dry-core (~> 0.4)
|
65
70
|
dry-equalizer (~> 0.2)
|
66
71
|
dry-initializer (~> 3.0)
|
67
|
-
dry-schema (~> 1.5
|
72
|
+
dry-schema (~> 1.5)
|
68
73
|
factory_bot (6.1.0)
|
69
74
|
activesupport (>= 5.0.0)
|
70
75
|
git (1.8.1)
|
@@ -79,10 +84,10 @@ GEM
|
|
79
84
|
parser (2.7.1.4)
|
80
85
|
ast (~> 2.4.1)
|
81
86
|
rainbow (3.0.0)
|
82
|
-
rake (13.0.
|
87
|
+
rake (13.0.6)
|
83
88
|
rchardet (1.8.0)
|
84
89
|
regexp_parser (1.7.1)
|
85
|
-
rexml (3.2.
|
90
|
+
rexml (3.2.5)
|
86
91
|
rspec (3.9.0)
|
87
92
|
rspec-core (~> 3.9.0)
|
88
93
|
rspec-expectations (~> 3.9.0)
|
@@ -133,4 +138,4 @@ DEPENDENCIES
|
|
133
138
|
simplecov (~> 0.17.0)
|
134
139
|
|
135
140
|
BUNDLED WITH
|
136
|
-
2.
|
141
|
+
2.2.24
|
data/README.md
CHANGED
@@ -27,7 +27,7 @@ If you use Rbenv you can install djin only once and create an alias in your .bas
|
|
27
27
|
To use djin first you need to create a djin.yml file:
|
28
28
|
|
29
29
|
```yaml
|
30
|
-
djin_version: '0.11.
|
30
|
+
djin_version: '0.11.7'
|
31
31
|
|
32
32
|
tasks:
|
33
33
|
# With a docker image
|
@@ -54,7 +54,7 @@ You can also set task dependencies with depends_on option:
|
|
54
54
|
|
55
55
|
|
56
56
|
```yaml
|
57
|
-
djin_version: '0.11.
|
57
|
+
djin_version: '0.11.7'
|
58
58
|
|
59
59
|
_default_run_options: &default_run_options
|
60
60
|
options: "--rm"
|
@@ -83,7 +83,7 @@ tasks:
|
|
83
83
|
Or mix local commands and docker/docker-compose commands:
|
84
84
|
|
85
85
|
```yaml
|
86
|
-
djin_version: '0.11.
|
86
|
+
djin_version: '0.11.7'
|
87
87
|
|
88
88
|
_default_run_options: &default_run_options
|
89
89
|
options: "--rm"
|
@@ -122,7 +122,7 @@ After that you can run `djin {{task_name}}`, like `djin script` or `djin test`
|
|
122
122
|
You can also use environment variables using the '{{YOUR_ENV_HERE}}' syntax, like so:
|
123
123
|
|
124
124
|
```yaml
|
125
|
-
djin_version: '0.11.
|
125
|
+
djin_version: '0.11.7'
|
126
126
|
|
127
127
|
_default_run_options: &default_run_options
|
128
128
|
options: "--rm"
|
@@ -139,7 +139,7 @@ tasks:
|
|
139
139
|
|
140
140
|
Or define some variables to use in multiple locations
|
141
141
|
```yaml
|
142
|
-
djin_version: '0.11.
|
142
|
+
djin_version: '0.11.7'
|
143
143
|
|
144
144
|
_default_run_options: &default_run_options
|
145
145
|
options: "--rm"
|
@@ -163,7 +163,7 @@ tasks:
|
|
163
163
|
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:
|
164
164
|
|
165
165
|
```yaml
|
166
|
-
djin_version: '0.11.
|
166
|
+
djin_version: '0.11.7'
|
167
167
|
|
168
168
|
_default_run_options: &default_run_options
|
169
169
|
options: "--rm"
|
@@ -189,7 +189,7 @@ Under the hood djin uses [Mustache](https://mustache.github.io/), so you can use
|
|
189
189
|
If you have multiple tasks with similar behavior and with small differences you can use the `include` keyword, so this:
|
190
190
|
|
191
191
|
```yaml
|
192
|
-
djin_version: '0.11.
|
192
|
+
djin_version: '0.11.7'
|
193
193
|
|
194
194
|
tasks:
|
195
195
|
"host1:ssh":
|
@@ -228,7 +228,7 @@ can become this:
|
|
228
228
|
|
229
229
|
```yaml
|
230
230
|
# djin.yml
|
231
|
-
djin_version: '0.11.
|
231
|
+
djin_version: '0.11.7'
|
232
232
|
|
233
233
|
include:
|
234
234
|
- file: '.djin/server_tasks.yml'
|
@@ -250,7 +250,7 @@ include:
|
|
250
250
|
|
251
251
|
```yaml
|
252
252
|
# .djin/server_tasks.yml
|
253
|
-
djin_version: '0.11.
|
253
|
+
djin_version: '0.11.7'
|
254
254
|
|
255
255
|
tasks:
|
256
256
|
"{{namespace}}:ssh":
|
@@ -272,7 +272,7 @@ tasks:
|
|
272
272
|
You can also reuse tasks in some git repository, to do that you need to declare a git source and optionally a version:
|
273
273
|
|
274
274
|
```yaml
|
275
|
-
djin_version: '0.11.
|
275
|
+
djin_version: '0.11.7'
|
276
276
|
|
277
277
|
include:
|
278
278
|
- git: 'https://github.com/catks/djin.git'
|
@@ -315,10 +315,9 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
315
315
|
|
316
316
|
## TODO
|
317
317
|
|
318
|
-
1.
|
319
|
-
2.
|
320
|
-
|
321
|
-
4. include a key option to add tasks in git repositories files (maybe with a local cache)
|
318
|
+
1. Option to export tasks to Makefile
|
319
|
+
2. djin-export docker image to create and sync makefiles
|
320
|
+
|
322
321
|
|
323
322
|
## Contributing
|
324
323
|
|
data/djin.gemspec
CHANGED
@@ -28,9 +28,14 @@ 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-configurable', '~> 0.9.0'
|
32
|
+
spec.add_dependency 'dry-container', '~> 0.7.0'
|
33
|
+
spec.add_dependency 'dry-core', '~> 0.6.0'
|
31
34
|
spec.add_dependency 'dry-equalizer', '~> 0.3.0'
|
35
|
+
spec.add_dependency 'dry-inflector', '~> 0.1.0'
|
36
|
+
spec.add_dependency 'dry-schema', '~> 1.6.0'
|
32
37
|
spec.add_dependency 'dry-struct', '~> 1.3.0'
|
33
|
-
spec.add_dependency 'dry-validation', '
|
38
|
+
spec.add_dependency 'dry-validation', '= 1.5.1'
|
34
39
|
spec.add_dependency 'git', '~> 1.8.1'
|
35
40
|
spec.add_dependency 'mustache', '~> 1.1.1'
|
36
41
|
spec.add_dependency 'vseries', '~> 0.1.0'
|
data/djin.yml
CHANGED
data/docker-entrypoint.sh
CHANGED
data/examples/djin.yml
CHANGED
data/examples/djin_lib/test.yml
CHANGED
data/lib/djin/cli.rb
CHANGED
@@ -13,6 +13,10 @@ module Djin
|
|
13
13
|
|
14
14
|
def call(**)
|
15
15
|
Executor.new.call(task)
|
16
|
+
# TODO: Extract error handling output (the same logic is used in djin.rb)
|
17
|
+
rescue Djin::TaskError => e
|
18
|
+
error_name = e.class.name.split('::').last
|
19
|
+
abort("[#{error_name}] #{e.message}")
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
data/lib/djin/config_loader.rb
CHANGED
@@ -1,36 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Djin
|
4
|
-
# TODO: Refactor this class to
|
5
|
-
#
|
6
|
-
#
|
4
|
+
# TODO: Refactor this class to delegate the responsability of complex fields
|
5
|
+
# to a specific Loader (like include for IncludeConfigLoader),
|
6
|
+
# maybe renaming to RootConfigLoader
|
7
7
|
|
8
8
|
# rubocop:disable Metrics/ClassLength
|
9
9
|
class ConfigLoader
|
10
10
|
using Djin::HashExtensions
|
11
11
|
RESERVED_WORDS = %w[djin_version variables tasks include].freeze
|
12
12
|
|
13
|
-
|
14
|
-
FileNotFoundError = Class.new(Interpreter::InvalidConfigurationError)
|
15
|
-
|
16
|
-
def self.load_files!(*files, runtime_config: {}, base_directory: '.')
|
13
|
+
def self.load_files!(*files, context_config: {}, base_directory: '.')
|
17
14
|
files.map do |file_path|
|
18
|
-
ConfigLoader.load!(file_path,
|
15
|
+
ConfigLoader.load!(file_path, context_config: context_config, base_directory: base_directory)
|
19
16
|
end&.reduce(:deep_merge)
|
20
17
|
end
|
21
18
|
|
22
|
-
def self.load!(template_file_path,
|
23
|
-
new(template_file_path,
|
19
|
+
def self.load!(template_file_path, context_config: {}, base_directory: '.')
|
20
|
+
new(template_file_path, context_config: context_config, base_directory: base_directory).load!
|
24
21
|
end
|
25
22
|
|
26
|
-
def initialize(template_file_path,
|
23
|
+
def initialize(template_file_path, context_config: {}, base_directory: '.')
|
27
24
|
@base_directory = Pathname.new(base_directory)
|
28
25
|
@template_file = @base_directory.join(template_file_path)
|
29
26
|
|
30
27
|
file_not_found!(@template_file) unless @template_file.exist?
|
31
28
|
|
32
29
|
@template_file_content = Djin.cache.fetch(@template_file.realpath.to_s) { @template_file.read }
|
33
|
-
@
|
30
|
+
@context_config = context_config
|
34
31
|
end
|
35
32
|
|
36
33
|
def load!
|
@@ -107,7 +104,7 @@ module Djin
|
|
107
104
|
present_include_configs&.map do |present_include|
|
108
105
|
ConfigLoader.load!(present_include.file, base_directory: @template_file.dirname,
|
109
106
|
# TODO: Rename to context_config
|
110
|
-
|
107
|
+
context_config: present_include.context)
|
111
108
|
end&.reduce(:deep_merge)
|
112
109
|
end
|
113
110
|
end
|
@@ -120,18 +117,9 @@ module Djin
|
|
120
117
|
include_configs&.select(&:missing?)
|
121
118
|
end
|
122
119
|
|
123
|
-
# TODO: Refactor to move include methods to a specific IncludeConfigLoader, maybe rename IncludeResolver
|
124
120
|
def include_configs
|
125
|
-
@include_configs ||=
|
126
|
-
|
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
|
121
|
+
@include_configs ||= Djin::IncludeConfigLoader.load!(raw_djin_config['include'],
|
122
|
+
base_directory: @template_file.dirname)
|
135
123
|
end
|
136
124
|
|
137
125
|
def args
|
@@ -147,9 +135,9 @@ module Djin
|
|
147
135
|
end
|
148
136
|
|
149
137
|
def raw_djin_config
|
150
|
-
@raw_djin_config ||= yaml_load(@template_file_content).deep_merge(@
|
138
|
+
@raw_djin_config ||= yaml_load(@template_file_content).deep_merge(@context_config)
|
151
139
|
rescue Psych::SyntaxError => e
|
152
|
-
raise
|
140
|
+
raise InvalidConfigFileError, "File: #{@template_file.realpath}\n #{e.message}"
|
153
141
|
end
|
154
142
|
|
155
143
|
def rendered_djin_config
|
@@ -160,7 +148,7 @@ module Djin
|
|
160
148
|
args: args.join(' '),
|
161
149
|
args?: args.any?,
|
162
150
|
**locals)
|
163
|
-
yaml_load(rendered_yaml).merge(@
|
151
|
+
yaml_load(rendered_yaml).merge(@context_config)
|
164
152
|
end
|
165
153
|
end
|
166
154
|
|
@@ -169,11 +157,11 @@ module Djin
|
|
169
157
|
end
|
170
158
|
|
171
159
|
def validate_version!
|
172
|
-
raise
|
160
|
+
raise MissingVersionError, 'Missing djin_version' unless version
|
173
161
|
|
174
162
|
return if file_config.version_supported?
|
175
163
|
|
176
|
-
raise
|
164
|
+
raise VersionNotSupportedError, "Version #{version} is not supported, the current version is #{Djin::VERSION}"
|
177
165
|
end
|
178
166
|
|
179
167
|
def validate_missing_config!
|
data/lib/djin/errors.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Djin
|
4
|
+
InvalidConfigurationError = Class.new(StandardError)
|
5
|
+
InvalidConfigFileError = Class.new(InvalidConfigurationError)
|
6
|
+
MissingVersionError = Class.new(InvalidConfigurationError)
|
7
|
+
VersionNotSupportedError = Class.new(InvalidConfigurationError)
|
8
|
+
InvalidSyntaxError = Class.new(InvalidConfigurationError)
|
9
|
+
FileNotFoundError = Class.new(InvalidConfigurationError)
|
10
|
+
|
11
|
+
TaskError = Class.new(StandardError)
|
12
|
+
end
|
data/lib/djin/executor.rb
CHANGED
@@ -19,12 +19,12 @@ module Djin
|
|
19
19
|
run_task dependent_task
|
20
20
|
end
|
21
21
|
|
22
|
-
run
|
23
|
-
run
|
22
|
+
run(task.build_command, task_name: task.name) if task.build_command
|
23
|
+
run(task.command, task_name: task.name) if task.command
|
24
24
|
end
|
25
25
|
|
26
|
-
def run(command)
|
27
|
-
system
|
26
|
+
def run(command, task_name:)
|
27
|
+
raise TaskError, "Task `#{task_name}` failed" unless system(command)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -1,10 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Djin
|
4
|
-
class
|
4
|
+
class IncludeConfigLoader
|
5
5
|
using ObjectExtensions
|
6
6
|
using HashExtensions
|
7
7
|
|
8
|
+
def self.load!(include_djin_config, **options)
|
9
|
+
new(**options).load!(include_djin_config)
|
10
|
+
end
|
11
|
+
|
8
12
|
def initialize(base_directory: '.', remote_directory: '~/.djin/remote', entity_class: Djin::IncludeConfig)
|
9
13
|
# TODO: Use chain of responsability
|
10
14
|
@base_directory = Pathname.new(base_directory)
|
@@ -12,15 +16,33 @@ module Djin
|
|
12
16
|
@entity_class = entity_class
|
13
17
|
end
|
14
18
|
|
15
|
-
def
|
19
|
+
def load!(include_djin_config)
|
20
|
+
load_configs(include_djin_config)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def load_configs(include_djin_config)
|
26
|
+
include_djin_config ||= []
|
27
|
+
|
28
|
+
include_contract = IncludeContract.new
|
29
|
+
|
30
|
+
include_djin_config.map do |include_params|
|
31
|
+
result = include_contract.call(include_params)
|
32
|
+
|
33
|
+
raise InvalidSyntaxError, { include: result.errors.to_h } if result.failure?
|
34
|
+
|
35
|
+
resolve_include(include_params)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def resolve_include(params)
|
16
40
|
include_config_params = remote_handler(params)
|
17
41
|
include_config_params ||= local_handler(params)
|
18
42
|
|
19
43
|
build_entity(include_config_params)
|
20
44
|
end
|
21
45
|
|
22
|
-
private
|
23
|
-
|
24
46
|
def remote_handler(params)
|
25
47
|
return if params['git'].blank?
|
26
48
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Djin
|
4
|
+
class IncludeContract < Dry::Validation::Contract
|
5
|
+
using Djin::ObjectExtensions
|
6
|
+
|
7
|
+
GIT_URI_REGEXP = Regexp.new('(\w+://)(.+@)*([\w\d\.]+)(:[\d]+){0,1}/*(.*)')
|
8
|
+
GIT_SSH_REGEXP = Regexp.new('(.+@)+([\w\d\.]+):(.*)')
|
9
|
+
GIT_FILE_REGEXP = Regexp.new('file://(.*)')
|
10
|
+
|
11
|
+
ContextSchema = Dry::Schema.Params do
|
12
|
+
optional(:variables).filled(:hash)
|
13
|
+
# TODO: Add the rest
|
14
|
+
end
|
15
|
+
|
16
|
+
params do
|
17
|
+
optional(:context).filled do
|
18
|
+
hash(ContextSchema)
|
19
|
+
end
|
20
|
+
required(:file).filled(:string)
|
21
|
+
optional(:git).filled(:string)
|
22
|
+
optional(:version).filled(:string)
|
23
|
+
end
|
24
|
+
|
25
|
+
rule(:git) do
|
26
|
+
key.failure("Invalid git uri in: #{value}") if value.present? && !valid_git_repository_path?(value)
|
27
|
+
end
|
28
|
+
|
29
|
+
# TODO: Add more validations to file and to restricted unespected keys
|
30
|
+
#
|
31
|
+
private
|
32
|
+
|
33
|
+
def valid_git_repository_path?(path)
|
34
|
+
[GIT_URI_REGEXP,
|
35
|
+
GIT_SSH_REGEXP,
|
36
|
+
GIT_FILE_REGEXP].any? { |regexp| regexp.match?(path) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/djin/interpreter.rb
CHANGED
@@ -1,16 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Djin
|
4
|
+
# TODO: Refactor to TaskConfigLoader and make COnfigLoader to use this class
|
4
5
|
class Interpreter
|
5
6
|
using Djin::HashExtensions
|
6
7
|
|
7
|
-
# TODO: Move Errors to ConfigLoader
|
8
|
-
InvalidConfigurationError = Class.new(StandardError)
|
9
|
-
InvalidConfigFileError = Class.new(InvalidConfigurationError)
|
10
|
-
MissingVersionError = Class.new(InvalidConfigurationError)
|
11
|
-
VersionNotSupportedError = Class.new(InvalidConfigurationError)
|
12
|
-
InvalidSyntaxError = Class.new(InvalidConfigurationError)
|
13
|
-
|
14
8
|
class << self
|
15
9
|
# rubocop:disable Metrics/AbcSize
|
16
10
|
def load!(file_config)
|
data/lib/djin/version.rb
CHANGED
data/lib/djin.rb
CHANGED
@@ -10,18 +10,20 @@ require 'dry/cli'
|
|
10
10
|
require 'mustache'
|
11
11
|
require 'optparse'
|
12
12
|
require 'git'
|
13
|
+
require 'djin/errors'
|
13
14
|
require 'djin/extensions/hash_extensions'
|
14
15
|
require 'djin/extensions/object_extensions'
|
15
16
|
require 'djin/entities/types'
|
16
17
|
require 'djin/entities/task'
|
17
18
|
require 'djin/entities/include_config.rb'
|
18
19
|
require 'djin/entities/main_config'
|
20
|
+
require 'djin/include_contract'
|
19
21
|
require 'djin/interpreter/base_command_builder'
|
20
22
|
require 'djin/interpreter/docker_command_builder'
|
21
23
|
require 'djin/interpreter/docker_compose_command_builder'
|
22
24
|
require 'djin/interpreter/local_command_builder'
|
23
25
|
require 'djin/interpreter'
|
24
|
-
require 'djin/
|
26
|
+
require 'djin/include_config_loader'
|
25
27
|
require 'djin/config_loader'
|
26
28
|
require 'djin/executor'
|
27
29
|
require 'djin/root_cli_parser'
|
@@ -51,7 +53,7 @@ module Djin
|
|
51
53
|
@remote_config_repository = RemoteConfigRepository.new(remote_configs)
|
52
54
|
|
53
55
|
CLI.load_tasks!(tasks)
|
54
|
-
rescue Djin::
|
56
|
+
rescue Djin::InvalidConfigurationError => e
|
55
57
|
error_name = e.class.name.split('::').last
|
56
58
|
abort("[#{error_name}] #{e.message}")
|
57
59
|
end
|
data/wait-for-it.sh
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
# Use this script to test if a given TCP host/port are available
|
3
|
+
# Credits: https://github.com/vishnubob/wait-for-it
|
4
|
+
|
5
|
+
WAITFORIT_cmdname=${0##*/}
|
6
|
+
|
7
|
+
echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
|
8
|
+
|
9
|
+
usage()
|
10
|
+
{
|
11
|
+
cat << USAGE >&2
|
12
|
+
Usage:
|
13
|
+
$WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
|
14
|
+
-h HOST | --host=HOST Host or IP under test
|
15
|
+
-p PORT | --port=PORT TCP port under test
|
16
|
+
Alternatively, you specify the host and port as host:port
|
17
|
+
-s | --strict Only execute subcommand if the test succeeds
|
18
|
+
-q | --quiet Don't output any status messages
|
19
|
+
-t TIMEOUT | --timeout=TIMEOUT
|
20
|
+
Timeout in seconds, zero for no timeout
|
21
|
+
-- COMMAND ARGS Execute command with args after the test finishes
|
22
|
+
USAGE
|
23
|
+
exit 1
|
24
|
+
}
|
25
|
+
|
26
|
+
wait_for()
|
27
|
+
{
|
28
|
+
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
|
29
|
+
echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
|
30
|
+
else
|
31
|
+
echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
|
32
|
+
fi
|
33
|
+
WAITFORIT_start_ts=$(date +%s)
|
34
|
+
while :
|
35
|
+
do
|
36
|
+
if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
|
37
|
+
nc -z $WAITFORIT_HOST $WAITFORIT_PORT
|
38
|
+
WAITFORIT_result=$?
|
39
|
+
else
|
40
|
+
(echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
|
41
|
+
WAITFORIT_result=$?
|
42
|
+
fi
|
43
|
+
if [[ $WAITFORIT_result -eq 0 ]]; then
|
44
|
+
WAITFORIT_end_ts=$(date +%s)
|
45
|
+
echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
|
46
|
+
break
|
47
|
+
fi
|
48
|
+
sleep 1
|
49
|
+
done
|
50
|
+
return $WAITFORIT_result
|
51
|
+
}
|
52
|
+
|
53
|
+
wait_for_wrapper()
|
54
|
+
{
|
55
|
+
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
|
56
|
+
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
|
57
|
+
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
|
58
|
+
else
|
59
|
+
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
|
60
|
+
fi
|
61
|
+
WAITFORIT_PID=$!
|
62
|
+
trap "kill -INT -$WAITFORIT_PID" INT
|
63
|
+
wait $WAITFORIT_PID
|
64
|
+
WAITFORIT_RESULT=$?
|
65
|
+
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
|
66
|
+
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
|
67
|
+
fi
|
68
|
+
return $WAITFORIT_RESULT
|
69
|
+
}
|
70
|
+
|
71
|
+
# process arguments
|
72
|
+
while [[ $# -gt 0 ]]
|
73
|
+
do
|
74
|
+
case "$1" in
|
75
|
+
*:* )
|
76
|
+
WAITFORIT_hostport=(${1//:/ })
|
77
|
+
WAITFORIT_HOST=${WAITFORIT_hostport[0]}
|
78
|
+
WAITFORIT_PORT=${WAITFORIT_hostport[1]}
|
79
|
+
shift 1
|
80
|
+
;;
|
81
|
+
--child)
|
82
|
+
WAITFORIT_CHILD=1
|
83
|
+
shift 1
|
84
|
+
;;
|
85
|
+
-q | --quiet)
|
86
|
+
WAITFORIT_QUIET=1
|
87
|
+
shift 1
|
88
|
+
;;
|
89
|
+
-s | --strict)
|
90
|
+
WAITFORIT_STRICT=1
|
91
|
+
shift 1
|
92
|
+
;;
|
93
|
+
-h)
|
94
|
+
WAITFORIT_HOST="$2"
|
95
|
+
if [[ $WAITFORIT_HOST == "" ]]; then break; fi
|
96
|
+
shift 2
|
97
|
+
;;
|
98
|
+
--host=*)
|
99
|
+
WAITFORIT_HOST="${1#*=}"
|
100
|
+
shift 1
|
101
|
+
;;
|
102
|
+
-p)
|
103
|
+
WAITFORIT_PORT="$2"
|
104
|
+
if [[ $WAITFORIT_PORT == "" ]]; then break; fi
|
105
|
+
shift 2
|
106
|
+
;;
|
107
|
+
--port=*)
|
108
|
+
WAITFORIT_PORT="${1#*=}"
|
109
|
+
shift 1
|
110
|
+
;;
|
111
|
+
-t)
|
112
|
+
WAITFORIT_TIMEOUT="$2"
|
113
|
+
if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
|
114
|
+
shift 2
|
115
|
+
;;
|
116
|
+
--timeout=*)
|
117
|
+
WAITFORIT_TIMEOUT="${1#*=}"
|
118
|
+
shift 1
|
119
|
+
;;
|
120
|
+
--)
|
121
|
+
shift
|
122
|
+
WAITFORIT_CLI=("$@")
|
123
|
+
break
|
124
|
+
;;
|
125
|
+
--help)
|
126
|
+
usage
|
127
|
+
;;
|
128
|
+
*)
|
129
|
+
echoerr "Unknown argument: $1"
|
130
|
+
usage
|
131
|
+
;;
|
132
|
+
esac
|
133
|
+
done
|
134
|
+
|
135
|
+
if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
|
136
|
+
echoerr "Error: you need to provide a host and port to test."
|
137
|
+
usage
|
138
|
+
fi
|
139
|
+
|
140
|
+
WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
|
141
|
+
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
|
142
|
+
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
|
143
|
+
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
|
144
|
+
|
145
|
+
# Check to see if timeout is from busybox?
|
146
|
+
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
|
147
|
+
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
|
148
|
+
|
149
|
+
WAITFORIT_BUSYTIMEFLAG=""
|
150
|
+
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
|
151
|
+
WAITFORIT_ISBUSY=1
|
152
|
+
# Check if busybox timeout uses -t flag
|
153
|
+
# (recent Alpine versions don't support -t anymore)
|
154
|
+
if timeout &>/dev/stdout | grep -q -e '-t '; then
|
155
|
+
WAITFORIT_BUSYTIMEFLAG="-t"
|
156
|
+
fi
|
157
|
+
else
|
158
|
+
WAITFORIT_ISBUSY=0
|
159
|
+
fi
|
160
|
+
|
161
|
+
if [[ $WAITFORIT_CHILD -gt 0 ]]; then
|
162
|
+
wait_for
|
163
|
+
WAITFORIT_RESULT=$?
|
164
|
+
exit $WAITFORIT_RESULT
|
165
|
+
else
|
166
|
+
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
|
167
|
+
wait_for_wrapper
|
168
|
+
WAITFORIT_RESULT=$?
|
169
|
+
else
|
170
|
+
wait_for
|
171
|
+
WAITFORIT_RESULT=$?
|
172
|
+
fi
|
173
|
+
fi
|
174
|
+
|
175
|
+
if [[ $WAITFORIT_CLI != "" ]]; then
|
176
|
+
if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
|
177
|
+
echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
|
178
|
+
exit $WAITFORIT_RESULT
|
179
|
+
fi
|
180
|
+
exec "${WAITFORIT_CLI[@]}"
|
181
|
+
else
|
182
|
+
exit $WAITFORIT_RESULT
|
183
|
+
fi
|
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.11.
|
4
|
+
version: 0.11.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carlos Atkinson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-cli
|
@@ -24,6 +24,48 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.6.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dry-configurable
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.9.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.9.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dry-container
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.7.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.7.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: dry-core
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.6.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.6.0
|
27
69
|
- !ruby/object:Gem::Dependency
|
28
70
|
name: dry-equalizer
|
29
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +80,34 @@ dependencies:
|
|
38
80
|
- - "~>"
|
39
81
|
- !ruby/object:Gem::Version
|
40
82
|
version: 0.3.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: dry-inflector
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.1.0
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.1.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: dry-schema
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.6.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.6.0
|
41
111
|
- !ruby/object:Gem::Dependency
|
42
112
|
name: dry-struct
|
43
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -56,14 +126,14 @@ dependencies:
|
|
56
126
|
name: dry-validation
|
57
127
|
requirement: !ruby/object:Gem::Requirement
|
58
128
|
requirements:
|
59
|
-
- -
|
129
|
+
- - '='
|
60
130
|
- !ruby/object:Gem::Version
|
61
131
|
version: 1.5.1
|
62
132
|
type: :runtime
|
63
133
|
prerelease: false
|
64
134
|
version_requirements: !ruby/object:Gem::Requirement
|
65
135
|
requirements:
|
66
|
-
- -
|
136
|
+
- - '='
|
67
137
|
- !ruby/object:Gem::Version
|
68
138
|
version: 1.5.1
|
69
139
|
- !ruby/object:Gem::Dependency
|
@@ -236,10 +306,12 @@ files:
|
|
236
306
|
- lib/djin/entities/main_config.rb
|
237
307
|
- lib/djin/entities/task.rb
|
238
308
|
- lib/djin/entities/types.rb
|
309
|
+
- lib/djin/errors.rb
|
239
310
|
- lib/djin/executor.rb
|
240
311
|
- lib/djin/extensions/hash_extensions.rb
|
241
312
|
- lib/djin/extensions/object_extensions.rb
|
242
|
-
- lib/djin/
|
313
|
+
- lib/djin/include_config_loader.rb
|
314
|
+
- lib/djin/include_contract.rb
|
243
315
|
- lib/djin/interpreter.rb
|
244
316
|
- lib/djin/interpreter/base_command_builder.rb
|
245
317
|
- lib/djin/interpreter/docker_command_builder.rb
|
@@ -251,6 +323,7 @@ files:
|
|
251
323
|
- lib/djin/root_cli_parser.rb
|
252
324
|
- lib/djin/task_contract.rb
|
253
325
|
- lib/djin/version.rb
|
326
|
+
- wait-for-it.sh
|
254
327
|
homepage: https://github.com/catks/djin
|
255
328
|
licenses:
|
256
329
|
- MIT
|
@@ -270,8 +343,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
270
343
|
- !ruby/object:Gem::Version
|
271
344
|
version: '0'
|
272
345
|
requirements: []
|
273
|
-
|
274
|
-
rubygems_version: 2.7.6
|
346
|
+
rubygems_version: 3.1.6
|
275
347
|
signing_key:
|
276
348
|
specification_version: 4
|
277
349
|
summary: djin is a make-like utility for docker containers
|