dip 8.0.0 → 8.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 027ac4456743eaef5ed3d2a461b15e57fcc13739500ef04bdedfca37b4c6c266
4
- data.tar.gz: e5cdc4f2597241c242bc91f007ab35a2392feafbf924109f97f48ff330228997
3
+ metadata.gz: f0797622a68dc23c6c015addd9a97dfe57d9c5cca6b4981054dbac9f5f7602c9
4
+ data.tar.gz: bdb1277acfa498846fdd737a13058dc1dfc272fbd7196d21e4cbfeefaf13b3a6
5
5
  SHA512:
6
- metadata.gz: 59685a0ab3f5d1174d58048d021b8f4f12d494aaa09773e0b0cfd05d4a2d12975c594efc7597b67e054912f5e6d75fdbd293ac7ca5ba69ab06af858f93dac1c5
7
- data.tar.gz: 505a3e3657f17a0c01e1d785bfb23a86982ee42da7a8185ccf753de0116e7f18d082d66d11bac07031e43600c9397a74728de62e0a6d70191f9dbe939080f2da
6
+ metadata.gz: 826f6e63b2cd65d20f6bfc00b545a7b5f60d6068786df01f841d92de1179d69fcced9605f65a3e4bfbcace583e5a20e7e8a660359ff2922685a02fae60c8c5c3
7
+ data.tar.gz: 5e583069000503b70df8a8466605d905c4937b931b53734de57486662a93a1f1991a51363e46687eeb4664879ece0ae1c9db56f9a76b57a6e5c478fa5e8d4ee9
data/README.md CHANGED
@@ -238,6 +238,92 @@ services:
238
238
 
239
239
  The container will run using the same user ID as your host machine.
240
240
 
241
+ ### Modules
242
+
243
+ Modules are defined as array in `modules` section of dip.yml, modules are stored in `.dip` subdirectory of dip.yml directory.
244
+
245
+ The main purpose of modules is to improve maintainability for a group of projects.
246
+ Imagine having multiple gems which are managed with dip, each of them has the same commands, so to change one command in dip you need to update all gems individualy.
247
+
248
+ With `modules` you can define a group of modules for dip.
249
+
250
+ For example having setup as this:
251
+
252
+ ```yml
253
+ # ./dip.yml
254
+ modules:
255
+ - sasts
256
+ - rails
257
+
258
+ ...
259
+ ```
260
+
261
+ ```yml
262
+ # ./.dip/sasts.yml
263
+ interaction:
264
+ brakeman:
265
+ description: Check brakeman sast
266
+ command: docker run ...
267
+ ```
268
+
269
+ ```yml
270
+ # ./.dip/rails.yml
271
+ interaction:
272
+ annotate:
273
+ description: Run annotate command
274
+ service: backend
275
+ command: bundle exec annotate
276
+ ```
277
+
278
+ Will be expanded to:
279
+
280
+ ```yml
281
+ # resultant configuration
282
+ interaction:
283
+ brakeman:
284
+ description: Check brakeman sast
285
+ command: docker run ...
286
+ annotate:
287
+ description: Run annotate command
288
+ service: backend
289
+ command: bundle exec annotate
290
+ ```
291
+
292
+ Imagine `.dip` to be a submodule so it can be managed only in one place.
293
+
294
+ If you want to override module command, you can redefine it in dip.yml
295
+
296
+ ```yml
297
+ # ./dip.yml
298
+ modules:
299
+ - sasts
300
+
301
+ interaction:
302
+ brakeman:
303
+ description: Check brakeman sast
304
+ command: docker run another-image ...
305
+ ```
306
+
307
+ ```yml
308
+ # ./.dip/sasts.yml
309
+ interaction:
310
+ brakeman:
311
+ description: Check brakeman sast
312
+ command: docker run some-image ...
313
+ ```
314
+
315
+ Will be expanded to:
316
+
317
+ ```yml
318
+ # resultant configuration
319
+ interaction:
320
+ brakeman:
321
+ description: Check brakeman sast
322
+ command: docker run another-image ...
323
+ ```
324
+
325
+ Nested modules are not supported.
326
+
241
327
  ### dip run
242
328
 
243
329
  Run commands defined within the `interaction` section of dip.yml
@@ -386,6 +472,27 @@ services:
386
472
  user: "1000:1000"
387
473
  ```
388
474
 
475
+ ### dip validate
476
+
477
+ Validates your dip.yml configuration against the JSON schema. The schema validation helps ensure your configuration is correct and follows the expected format.
478
+
479
+ ```sh
480
+ dip validate
481
+ ```
482
+
483
+ The validator will check:
484
+
485
+ - Required properties are present
486
+ - Property types are correct
487
+ - Values match expected patterns
488
+ - No unknown properties are used
489
+
490
+ If validation fails, you'll get detailed error messages indicating what needs to be fixed.
491
+
492
+ You can skip validation by setting `DIP_SKIP_VALIDATION` environment variable.
493
+
494
+ Add `# yaml-language-server: $schema=https://raw.githubusercontent.com/bibendi/dip/refs/heads/master/schema.json` to the top of your dip.yml to get schema validation in VSCode. Read more about [YAML Language Server](https://github.com/redhat-developer/vscode-yaml?tab=readme-ov-file#associating-schemas).
495
+
389
496
  ## Changelog
390
497
 
391
498
  https://github.com/bibendi/dip/releases
data/lib/dip/cli.rb CHANGED
@@ -5,7 +5,7 @@ require "dip/run_vars"
5
5
 
6
6
  module Dip
7
7
  class CLI < Thor
8
- TOP_LEVEL_COMMANDS = %w[help version ls compose up stop down run provision ssh infra console].freeze
8
+ TOP_LEVEL_COMMANDS = %w[help version ls compose up stop down run provision ssh infra console validate]
9
9
 
10
10
  class << self
11
11
  # Hackery. Take the run method away from Thor so that we can redefine it.
@@ -117,6 +117,15 @@ module Dip
117
117
  end
118
118
  end
119
119
 
120
+ desc "validate", "Validate the dip.yml file against the schema"
121
+ def validate
122
+ Dip.config.validate
123
+ puts "dip.yml is valid"
124
+ rescue Dip::Error => e
125
+ warn "Validation failed: #{e.message}"
126
+ exit 1
127
+ end
128
+
120
129
  require_relative "cli/ssh"
121
130
  desc "ssh", "ssh-agent container commands"
122
131
  subcommand :ssh, Dip::CLI::SSH
data/lib/dip/config.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require "yaml"
4
4
  require "erb"
5
5
  require "pathname"
6
+ require "json-schema"
6
7
 
7
8
  require "dip/version"
8
9
  require "dip/ext/hash"
@@ -43,6 +44,10 @@ module Dip
43
44
  file_path&.exist?
44
45
  end
45
46
 
47
+ def modules_dir
48
+ file_path.dirname / ".dip"
49
+ end
50
+
46
51
  private
47
52
 
48
53
  attr_reader :override
@@ -90,6 +95,10 @@ module Dip
90
95
  finder.file_path
91
96
  end
92
97
 
98
+ def module_file(filename)
99
+ finder.modules_dir / "#{filename}.yml"
100
+ end
101
+
93
102
  def exist?
94
103
  finder.exist?
95
104
  end
@@ -104,6 +113,24 @@ module Dip
104
113
  end
105
114
  end
106
115
 
116
+ def validate
117
+ raise Dip::Error, "Config file path is not set" if file_path.nil?
118
+ raise Dip::Error, "Config file not found: #{file_path}" unless File.exist?(file_path)
119
+
120
+ schema_path = File.join(File.dirname(__FILE__), "../../schema.json")
121
+ raise Dip::Error, "Schema file not found: #{schema_path}" unless File.exist?(schema_path)
122
+
123
+ data = YAML.load_file(file_path)
124
+ schema = JSON.parse(File.read(schema_path))
125
+ JSON::Validator.validate!(schema, data)
126
+ rescue Psych::SyntaxError => e
127
+ raise Dip::Error, "Invalid YAML syntax in config file: #{e.message}"
128
+ rescue JSON::Schema::ValidationError => e
129
+ data_display = data ? data.to_yaml.gsub("\n", "\n ") : "nil"
130
+ error_message = "Schema validation failed: #{e.message}\nInput data:\n #{data_display}"
131
+ raise Dip::Error, error_message
132
+ end
133
+
107
134
  private
108
135
 
109
136
  attr_reader :work_dir
@@ -121,14 +148,38 @@ module Dip
121
148
 
122
149
  unless Gem::Version.new(Dip::VERSION) >= Gem::Version.new(config.fetch(:version))
123
150
  raise VersionMismatchError, "Your dip version is `#{Dip::VERSION}`, " \
124
- "but config requires minimum version `#{config[:version]}`. " \
125
- "Please upgrade your dip!"
151
+ "but config requires minimum version `#{config[:version]}`. " \
152
+ "Please upgrade your dip!"
126
153
  end
127
154
 
155
+ base_config = {}
156
+
157
+ if (modules = config[:modules])
158
+ raise Dip::Error, "Modules should be specified as array" unless modules.is_a?(Array)
159
+
160
+ modules.each do |m|
161
+ file = module_file(m)
162
+ raise Dip::Error, "Could not find module `#{m}`" unless file.exist?
163
+
164
+ module_config = self.class.load_yaml(file)
165
+ raise Dip::Error, "Nested modules are not supported" if module_config[:modules]
166
+
167
+ base_config.deep_merge!(module_config)
168
+ end
169
+ end
170
+
171
+ base_config.deep_merge!(config)
172
+
128
173
  override_finder = ConfigFinder.new(work_dir, override: true)
129
- config.deep_merge!(self.class.load_yaml(override_finder.file_path)) if override_finder.exist?
174
+ base_config.deep_merge!(self.class.load_yaml(override_finder.file_path)) if override_finder.exist?
175
+
176
+ @config = CONFIG_DEFAULTS.merge(base_config)
177
+
178
+ unless ENV.key?("DIP_SKIP_VALIDATION")
179
+ validate
180
+ end
130
181
 
131
- @config = CONFIG_DEFAULTS.merge(config)
182
+ @config
132
183
  end
133
184
 
134
185
  def config_missing_error(config_key)
data/lib/dip/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dip
4
- VERSION = "8.0.0"
4
+ VERSION = "8.2.0"
5
5
  end
data/schema.json ADDED
@@ -0,0 +1,224 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-06/schema#",
3
+ "title": "Dip Configuration Schema",
4
+ "description": "Schema for the dip.yml configuration file",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "definitions": {
8
+ "environment_vars": {
9
+ "type": "object",
10
+ "description": "Defines environment variables",
11
+ "additionalProperties": {
12
+ "type": "string"
13
+ },
14
+ "examples": [
15
+ { "RAILS_ENV": "development" },
16
+ { "DATABASE_URL": "postgres://user:password@db:5432/myapp_development" },
17
+ { "PORT": "${PORT:-3000}" }
18
+ ]
19
+ },
20
+ "interaction_command": {
21
+ "type": "object",
22
+ "description": "Configuration for an interaction command",
23
+ "additionalProperties": false,
24
+ "properties": {
25
+ "description": {
26
+ "type": "string",
27
+ "description": "Describes the command",
28
+ "examples": ["Run Rails commands", "Connect to PostgreSQL database"]
29
+ },
30
+ "service": {
31
+ "type": "string",
32
+ "description": "Specifies the service associated with the command",
33
+ "examples": ["web", "frontend", "db"]
34
+ },
35
+ "command": {
36
+ "type": "string",
37
+ "description": "Represents the command to be executed",
38
+ "examples": ["bundle exec rails", "npm", "psql -h db -U user myapp_development"]
39
+ },
40
+ "default_args": {
41
+ "type": "string",
42
+ "description": "Default arguments for the command",
43
+ "examples": ["server -p 3000 -b 0.0.0.0"]
44
+ },
45
+ "environment": {
46
+ "$ref": "#/definitions/environment_vars"
47
+ },
48
+ "compose": {
49
+ "type": "object",
50
+ "description": "Allows specifying Docker Compose options",
51
+ "additionalProperties": false,
52
+ "properties": {
53
+ "method": {
54
+ "type": "string",
55
+ "description": "Specifies the Docker Compose method (e.g., up, run)",
56
+ "examples": ["run", "up"]
57
+ },
58
+ "compose_method": {
59
+ "type": "string",
60
+ "description": "Specifies an alternative Docker Compose method to use in compose commands",
61
+ "examples": ["up"]
62
+ },
63
+ "run_options": {
64
+ "type": "array",
65
+ "items": {
66
+ "type": "string"
67
+ },
68
+ "description": "Options to pass to the 'docker-compose run' command",
69
+ "examples": [["service-ports", "rm"]]
70
+ },
71
+ "profiles": {
72
+ "type": "array",
73
+ "items": {
74
+ "type": "string"
75
+ },
76
+ "description": "Docker Compose profiles to use",
77
+ "examples": [["web", "development"], ["frontend"], ["test"]]
78
+ }
79
+ }
80
+ },
81
+ "shell": {
82
+ "type": "boolean",
83
+ "description": "Enables or disables shell interpolation"
84
+ },
85
+ "entrypoint": {
86
+ "type": "string",
87
+ "description": "Specifies the command entrypoint"
88
+ },
89
+ "runner": {
90
+ "type": "string",
91
+ "description": "Specifies the runner (e.g., docker_compose, kubectl)"
92
+ },
93
+ "subcommands": {
94
+ "type": "object",
95
+ "description": "Contains subcommands with the same structure as main commands",
96
+ "patternProperties": {
97
+ "^[a-zA-Z0-9_]+$": {
98
+ "$ref": "#/definitions/interaction_command"
99
+ }
100
+ },
101
+ "minProperties": 1,
102
+ "additionalProperties": false
103
+ }
104
+ }
105
+ }
106
+ },
107
+ "properties": {
108
+ "version": {
109
+ "type": "string",
110
+ "description": "Specifies the minimum required version of Dip",
111
+ "examples": ["8.1.0"]
112
+ },
113
+ "compose": {
114
+ "type": "object",
115
+ "description": "Contains Docker Compose configuration",
116
+ "properties": {
117
+ "files": {
118
+ "type": "array",
119
+ "items": {
120
+ "type": "string"
121
+ },
122
+ "description": "Array of strings representing paths to Docker Compose files",
123
+ "examples": [["docker-compose.yml", "docker-compose.override.yml"]]
124
+ },
125
+ "project_name": {
126
+ "type": "string",
127
+ "description": "Specifies the project name for Docker Compose",
128
+ "examples": ["app"]
129
+ },
130
+ "command": {
131
+ "type": "string",
132
+ "description": "Specifies an alternative Docker Compose command",
133
+ "examples": ["docker compose"]
134
+ },
135
+ "method": {
136
+ "type": "string",
137
+ "description": "Specifies the Docker Compose method to use"
138
+ }
139
+ }
140
+ },
141
+ "interaction": {
142
+ "type": "object",
143
+ "description": "Defines the commands and their configurations",
144
+ "patternProperties": {
145
+ "^[a-zA-Z0-9_]+$": {
146
+ "$ref": "#/definitions/interaction_command"
147
+ }
148
+ },
149
+ "additionalProperties": false
150
+ },
151
+ "provision": {
152
+ "type": "array",
153
+ "items": {
154
+ "type": "string"
155
+ },
156
+ "description": "Lists the commands to be executed for provisioning",
157
+ "examples": [
158
+ [
159
+ "dip compose down --volumes",
160
+ "dip compose build",
161
+ "dip rails db:migrate",
162
+ "dip npm install"
163
+ ]
164
+ ]
165
+ },
166
+ "environment": {
167
+ "$ref": "#/definitions/environment_vars"
168
+ },
169
+ "kubectl": {
170
+ "type": "object",
171
+ "description": "Contains Kubernetes configuration",
172
+ "additionalProperties": false,
173
+ "properties": {
174
+ "namespace": {
175
+ "type": "string",
176
+ "description": "Specifies the Kubernetes namespace to use",
177
+ "examples": ["app"]
178
+ }
179
+ }
180
+ },
181
+ "modules": {
182
+ "type": "array",
183
+ "items": {
184
+ "type": "string"
185
+ },
186
+ "description": "Paths to module configuration files",
187
+ "examples": [["production"]]
188
+ },
189
+ "infra": {
190
+ "type": "object",
191
+ "description": "Contains infrastructure services configuration",
192
+ "additionalProperties": false,
193
+ "patternProperties": {
194
+ "^[a-zA-Z0-9_]+$": {
195
+ "type": "object",
196
+ "additionalProperties": false,
197
+ "properties": {
198
+ "git": {
199
+ "type": "string",
200
+ "pattern": "^(git@|git://|https?://)[\\w\\d\\.@:\\-/]+$",
201
+ "description": "Git repository URL for the infrastructure component",
202
+ "examples": ["https://github.com/mycompany/redis-config.git"]
203
+ },
204
+ "ref": {
205
+ "type": "string",
206
+ "description": "Specifies the Git reference (branch, tag, or commit) to use",
207
+ "examples": ["main"]
208
+ },
209
+ "path": {
210
+ "type": "string",
211
+ "description": "Local path to the infrastructure component",
212
+ "examples": ["./infra/elasticsearch"]
213
+ }
214
+ },
215
+ "oneOf": [
216
+ { "required": ["git", "ref"] },
217
+ { "required": ["path"] }
218
+ ]
219
+ }
220
+ }
221
+ }
222
+ },
223
+ "required": ["version", "interaction"]
224
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dip
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.0
4
+ version: 8.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - bibendi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-29 00:00:00.000000000 Z
11
+ date: 2024-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -30,6 +30,40 @@ dependencies:
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '2'
33
+ - !ruby/object:Gem::Dependency
34
+ name: json-schema
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '5'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5'
47
+ - !ruby/object:Gem::Dependency
48
+ name: public_suffix
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 2.0.2
54
+ - - "<"
55
+ - !ruby/object:Gem::Version
56
+ version: '6.0'
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 2.0.2
64
+ - - "<"
65
+ - !ruby/object:Gem::Version
66
+ version: '6.0'
33
67
  - !ruby/object:Gem::Dependency
34
68
  name: bundler
35
69
  requirement: !ruby/object:Gem::Requirement
@@ -212,6 +246,7 @@ files:
212
246
  - lib/dip/interaction_tree.rb
213
247
  - lib/dip/run_vars.rb
214
248
  - lib/dip/version.rb
249
+ - schema.json
215
250
  homepage: https://github.com/bibendi/dip
216
251
  licenses:
217
252
  - MIT
@@ -232,7 +267,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
232
267
  - !ruby/object:Gem::Version
233
268
  version: '0'
234
269
  requirements: []
235
- rubygems_version: 3.2.32
270
+ rubygems_version: 3.5.21
236
271
  signing_key:
237
272
  specification_version: 4
238
273
  summary: Ruby gem CLI tool for better interacting Docker Compose files.