jade_systems_toolbox 0.1.4 → 0.2.1
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/.rubocop.yml +1 -1
- data/.vscode/settings.json +2 -1
- data/README.md +93 -12
- data/lib/jade_systems_toolbox/cli.rb +129 -77
- data/lib/jade_systems_toolbox/docker_initializer.rb +43 -0
- data/lib/jade_systems_toolbox/http.rb +33 -0
- data/lib/jade_systems_toolbox/version.rb +1 -1
- data/lib/jade_systems_toolbox/vscode.rb +52 -0
- data/lib/jade_systems_toolbox.rb +3 -1
- data/templates/.devcontainer.json +36 -0
- metadata +12 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6e5e58dc71de22b037aab057b8a9205361a239590b6b844f438b59fdd771441f
|
|
4
|
+
data.tar.gz: 1b6a2766065ad815318eb62d463c3d5113ac3ed4b6e293c6aa883f6b3e174845
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 257d930928d5186d49415b1cc25b28122e5dada2753610ef3346ef39aa6174b01c89a43dfa567464caca71ea0c23982d9bb876e544e1fd4ae2fed4c4b29548e7
|
|
7
|
+
data.tar.gz: 51ea308a86ef16a12d8d2cb43dbe300558e3b97ed4aa0fe009834ad6c226121c58cc3e287639132f425f0d50ae2da3b907b9698349e9ec9775df551dd9eb28b6
|
data/.rubocop.yml
CHANGED
data/.vscode/settings.json
CHANGED
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
This gem installs a program to help do container-based development. It provides functions to:
|
|
4
4
|
|
|
5
5
|
* Prepare a directory for development in containers, including some files to configure VScode.
|
|
6
|
-
*
|
|
6
|
+
* Start the container(s).
|
|
7
7
|
* Open VScode on the code in the container.
|
|
8
8
|
* Open a browser window on the application-under-development's web server.
|
|
9
9
|
* Open a terminal session on the application container.
|
|
@@ -29,19 +29,21 @@ gem install --user-install jade_systems_toolbox
|
|
|
29
29
|
|
|
30
30
|
```terminal
|
|
31
31
|
Commands:
|
|
32
|
-
tool down
|
|
32
|
+
tool down -- [COMPOSE_ARGS] # docker compose down. Deletes the container. You probably want stop.
|
|
33
33
|
tool edit # devcontainer open
|
|
34
|
+
tool exec COMMAND [ARGS] # Run a command in the container and exit
|
|
34
35
|
tool help [COMMAND] # Describe available commands or one specific command
|
|
35
36
|
tool init # Initialize compose files and devcontainer.json
|
|
36
37
|
tool initialize_docker # Initialize compose files
|
|
37
|
-
tool
|
|
38
|
-
tool open # Open a page on the services's first port
|
|
38
|
+
tool initialize_vscode # Initialize devcontainer.json for vscode
|
|
39
|
+
tool open # Open a page on the services's first port or specified port
|
|
39
40
|
tool port [CONTAINER_PORT] # Get the host port for the CONTAINER_PORT's container port CONTAINER_PORT
|
|
40
41
|
tool ports # Get the host ports for the container ports defined in `compose.yml`
|
|
41
42
|
tool server [COMMAND] # Run the server in the container
|
|
43
|
+
tool start [COMPOSE_ARGS] # docker compose up -d (aliased as `up`)
|
|
42
44
|
tool stop # Stop the service(s) but preserve the container(s)
|
|
43
45
|
tool terminal # Run a shell in the container
|
|
44
|
-
tool
|
|
46
|
+
tool tree # Print a tree of all available commands
|
|
45
47
|
tool version # Show the version number of the tool.
|
|
46
48
|
|
|
47
49
|
Options:
|
|
@@ -56,7 +58,7 @@ The broad steps to start a brand new project are:
|
|
|
56
58
|
1. Create a directory for the project, and change directory into the new directory.
|
|
57
59
|
1. Decide which container(s) you want to use.
|
|
58
60
|
1. Initialize the container(s).
|
|
59
|
-
1.
|
|
61
|
+
1. Start the container(s).
|
|
60
62
|
1. Open a terminal session and create the application (e.g. `rails new` if you're doing a Rails project.)
|
|
61
63
|
1. Run the editor and otherwise do what you need to do to create your project.
|
|
62
64
|
1. When the web server is ready to run (if you're developing a web app), run the server.
|
|
@@ -83,7 +85,9 @@ tool init
|
|
|
83
85
|
|
|
84
86
|
The initialization installs
|
|
85
87
|
|
|
86
|
-
* A `compose.yml` file for Rails development with a SQLite database, using
|
|
88
|
+
* A `compose.yml` file for Rails development with a SQLite database, using the latest released version of Ruby,
|
|
89
|
+
and the latest stable version of Debian.
|
|
90
|
+
(Give or take. We don't track the releases so closely. Raise and issue if you need an upgrade.)
|
|
87
91
|
* On Linux, a `compose.override.yml` file.
|
|
88
92
|
* A `.devcontainer.json` file, so VScode can edit without the context of the container.
|
|
89
93
|
* `.vscode/settings.json` and `vscode/extensions.json` so developers have a consistent experience in VScode (mostly linting and autoformatting).
|
|
@@ -102,19 +106,37 @@ To choose a different ruby version and Debian version:
|
|
|
102
106
|
tool init --ruby-version 3.2 --distro-version bullseye
|
|
103
107
|
```
|
|
104
108
|
|
|
109
|
+
A fairly common variant is to get a `compose.yml` that also has a Playwright container:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
tool init --end-to-end-tool playwright
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
This retrieves the compose file, and puts it in your local `compose.yml`.
|
|
116
|
+
|
|
105
117
|
You can choose a currently supported Ruby version, and a Debian version that supports that Ruby version, from the containers built by https://github.com/lcreid/docker.
|
|
106
118
|
|
|
107
|
-
You're free to modify the `compose.yml` (and `compose.override.yml` on Linux).
|
|
119
|
+
You're free to modify the `compose.yml` (and `compose.override.yml` on Linux). Note that if you run `tool init` again, it will over-write your changes.
|
|
108
120
|
|
|
109
121
|
#### Start the Containers
|
|
110
122
|
|
|
111
123
|
```bash
|
|
112
|
-
tool
|
|
124
|
+
tool start
|
|
113
125
|
```
|
|
114
126
|
|
|
115
127
|
This takes a while to run, the first time you run it when the image isn't already downloaded to your computer.
|
|
116
128
|
|
|
117
|
-
|
|
129
|
+
You can add additional Docker Compose arguments to the command line. For example:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
tool start --remove-orphans
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
If any of the Docker Compose arguments are the same as any of `tool`'s arguments,
|
|
136
|
+
separate the `start` command from the rest of the command line with `--`,
|
|
137
|
+
like this: `tool start -- -v`.
|
|
138
|
+
|
|
139
|
+
#### Open a Terminal Session
|
|
118
140
|
|
|
119
141
|
```bash
|
|
120
142
|
tool terminal
|
|
@@ -126,6 +148,14 @@ This connects to the `web` service defined in the `compose.yml` file. If you wan
|
|
|
126
148
|
tool terminal --service mysql
|
|
127
149
|
```
|
|
128
150
|
|
|
151
|
+
Set some environment variables in the container (the `docker compose --env` flag):
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
tool terminal -e RAILS_ENV=test
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`tool terminal` supports the `--mapping` argument as described under [Run the Server](run-the-server).
|
|
158
|
+
|
|
129
159
|
#### Start VScode
|
|
130
160
|
|
|
131
161
|
```bash
|
|
@@ -138,10 +168,22 @@ tool edit
|
|
|
138
168
|
tool server
|
|
139
169
|
```
|
|
140
170
|
|
|
171
|
+
By default, the container has environment variables set for port mapping.
|
|
172
|
+
The container environment will have variables named `HOST_PORT_xxxx`,
|
|
173
|
+
and `xxxx` is the container port (e.g. 3000).
|
|
174
|
+
The _value_ of each environment variable
|
|
175
|
+
is the host's port number that the container port is mapped to.
|
|
176
|
+
|
|
177
|
+
If you don't want the mapping, you can turn it off:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
tool server --no-mapping
|
|
181
|
+
```
|
|
182
|
+
|
|
141
183
|
This runs `bin/dev`. To run something else, e.g. a bare Puma so you can debug it:
|
|
142
184
|
|
|
143
185
|
```bash
|
|
144
|
-
tool server
|
|
186
|
+
tool server bin/rails s -b 0.0.0.0
|
|
145
187
|
```
|
|
146
188
|
|
|
147
189
|
If you have other services running servers, or the server is in a sub-directory of your project:
|
|
@@ -152,6 +194,8 @@ tool server --work-dir test/app --service monitor
|
|
|
152
194
|
|
|
153
195
|
To terminate the server, type Control-C.
|
|
154
196
|
|
|
197
|
+
`tool server` supports the `--env` argument as described under [Open a Terminal Session](open-a-terminal-session).
|
|
198
|
+
|
|
155
199
|
#### Open a Browser Window
|
|
156
200
|
|
|
157
201
|
To connect to the server running on service `web` on port 3000:
|
|
@@ -184,6 +228,33 @@ tool open --path letter_opener
|
|
|
184
228
|
tool stop
|
|
185
229
|
```
|
|
186
230
|
|
|
231
|
+
You can add additional Docker Compose arguments to the command line. For example:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
tool stop --remove-orphans
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
If any of the Docker Compose arguments are the same as any of `tool`'s arguments,
|
|
238
|
+
separate the `exec` command from the rest of the command line with `--`,
|
|
239
|
+
like this: `tool stop -- -v`.
|
|
240
|
+
|
|
241
|
+
#### Run a Single Command in a Container
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
tool exec ls -l ..
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Some things to watch for:
|
|
248
|
+
|
|
249
|
+
- If any of the Docker Compose arguments are the same as any of `tool`'s arguments,
|
|
250
|
+
separate the `exec` command from the rest of the command line with `--`,
|
|
251
|
+
like this: `tool exec -- ls -l -t ..`.
|
|
252
|
+
- The shell on the host processes the command line,
|
|
253
|
+
so you need to quote or escape the command if you want variable expansion
|
|
254
|
+
and other shell features to happen in the container.
|
|
255
|
+
For example: `tool exec ls -l '$HOME'` to show the home directory in the container, not your home directory
|
|
256
|
+
(which probably doesn't exist in the container).
|
|
257
|
+
|
|
187
258
|
#### Bring Down the Containers
|
|
188
259
|
|
|
189
260
|
This destroys the containers, which will likely destroy all your gems.
|
|
@@ -192,6 +263,16 @@ This destroys the containers, which will likely destroy all your gems.
|
|
|
192
263
|
tool down
|
|
193
264
|
```
|
|
194
265
|
|
|
266
|
+
You can add additional Docker Compose arguments to the command line. For example: NOTE THAT THE FOLLOWING COMMAND IS VERY DESTRUCTIVE. It destroys the volume where you might have your development and test databases, or other important data:
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
tool down --volumes --remove-orphans
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
If any of the Docker Compose arguments are the same as any of `tool`'s arguments,
|
|
273
|
+
separate the `exec` command from the rest of the command line with `--`,
|
|
274
|
+
like this: `tool down -- -v`.
|
|
275
|
+
|
|
195
276
|
Skip the confirmation mesage with:
|
|
196
277
|
|
|
197
278
|
```bash
|
|
@@ -214,7 +295,7 @@ To run in another directory, use the path from the directory you're in, to the d
|
|
|
214
295
|
ruby -I ../jade_systems_toolbox/lib ../jade_systems_toolbox/exe/tool [COMMAND]
|
|
215
296
|
```
|
|
216
297
|
|
|
217
|
-
To install this gem onto your local machine, build it: `gem build jade_systems_toolbox.gemspec`, and install it: `gem install -l jade_systems_toolbox-0.
|
|
298
|
+
To install this gem onto your local machine, build it: `gem build jade_systems_toolbox.gemspec`, and install it: `gem install -l jade_systems_toolbox-0.2.0.gem`. (Change the version number to match the current version number.)
|
|
218
299
|
|
|
219
300
|
## Release
|
|
220
301
|
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
module JadeSystemsToolbox
|
|
4
4
|
class Cli < Thor
|
|
5
|
-
|
|
6
|
-
check_unknown_options!
|
|
5
|
+
stop_on_unknown_option! :down
|
|
7
6
|
|
|
8
7
|
class << self
|
|
8
|
+
# This and other improvements from Matt: https://mattbrictson.com/blog/fixing-thor-cli-behavior
|
|
9
9
|
def exit_on_failure? = true
|
|
10
10
|
end
|
|
11
11
|
|
|
@@ -14,13 +14,13 @@ module JadeSystemsToolbox
|
|
|
14
14
|
|
|
15
15
|
class_option :verbose, type: :boolean, default: false, aliases: "-v"
|
|
16
16
|
|
|
17
|
-
desc "down", "docker compose down. Deletes the container. You probably want stop."
|
|
17
|
+
desc "down -- [COMPOSE_ARGS]", "docker compose down. Deletes the container. You probably want stop."
|
|
18
18
|
option :force, default: "n", aliases: "-f"
|
|
19
|
-
def down
|
|
20
|
-
force = ask("tool down destroys the containers. Are you sure?").downcase unless options[:force] == "y"
|
|
19
|
+
def down(*compose_args)
|
|
20
|
+
force = ask("tool down destroys the containers. Are you sure [y/N]?").downcase unless options[:force] == "y"
|
|
21
21
|
exit(1) if force[0] != "y"
|
|
22
22
|
|
|
23
|
-
system("docker compose down")
|
|
23
|
+
system(([ "docker compose down" ] + compose_args).join(" "))
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
desc "edit", "devcontainer open"
|
|
@@ -28,57 +28,64 @@ module JadeSystemsToolbox
|
|
|
28
28
|
`devcontainer open`
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
desc "exec COMMAND [ARGS]", "Run a command in the container and exit"
|
|
32
|
+
option :env, repeatable: true, default: [], aliases: "-e", banner: "VAR=value"
|
|
33
|
+
option :mapping, type: :boolean, default: true, aliases: "-m"
|
|
34
|
+
option :service, default: "web", aliases: "-s"
|
|
35
|
+
option :work_dir, aliases: "-w"
|
|
36
|
+
def exec(command_for_container, *args)
|
|
37
|
+
service = options[:service]
|
|
38
|
+
workdir = "-w #{options[:work_dir]} " unless options[:work_dir].nil?
|
|
39
|
+
environment_variables = options[:env].map { "-e #{_1}" }.join(" ")
|
|
40
|
+
port_map_environment_variables = port_map_for_environment(service) if options[:mapping]
|
|
41
|
+
shell_command = [ command_for_container, *args ].join(" ")
|
|
42
|
+
command = [
|
|
43
|
+
"docker compose exec",
|
|
44
|
+
environment_variables,
|
|
45
|
+
port_map_environment_variables,
|
|
46
|
+
workdir,
|
|
47
|
+
"-it",
|
|
48
|
+
service,
|
|
49
|
+
"sh -c",
|
|
50
|
+
"'#{shell_command}'",
|
|
51
|
+
].compact.join(" ")
|
|
52
|
+
|
|
53
|
+
system(command)
|
|
54
|
+
end
|
|
55
|
+
|
|
31
56
|
desc "init", "Initialize compose files and devcontainer.json"
|
|
32
|
-
option :compose_file, default: "compose.yml"
|
|
33
57
|
option :database, default: "sqlite", aliases: "-d"
|
|
34
|
-
option :ruby_version, default: "
|
|
35
|
-
option :distro_version, default: "
|
|
58
|
+
option :ruby_version, default: "4.0", aliases: "-r"
|
|
59
|
+
option :distro_version, default: "trixie", aliases: "-t" # For Toy Story.
|
|
36
60
|
def init
|
|
37
61
|
invoke :initialize_docker
|
|
38
62
|
invoke :initialize_vscode, [], {}
|
|
39
63
|
end
|
|
40
64
|
|
|
41
65
|
desc "initialize_docker", "Initialize compose files"
|
|
42
|
-
option :compose_file, default: "compose.yml"
|
|
43
66
|
option :database, default: "sqlite", aliases: "-d"
|
|
44
|
-
option :ruby_version, default: "
|
|
45
|
-
option :distro_version, default: "
|
|
67
|
+
option :ruby_version, default: "4.0", aliases: "-r"
|
|
68
|
+
option :distro_version, default: "trixie", aliases: "-t" # For Toy Story.
|
|
69
|
+
method_option :end_to_end_tool,
|
|
70
|
+
type: :string,
|
|
71
|
+
enum: [ "playwright", "selenium" ],
|
|
72
|
+
desc: "Use an end-to-end (browser) testing tool",
|
|
73
|
+
aliases: "-e"
|
|
46
74
|
def initialize_docker
|
|
47
|
-
|
|
48
|
-
"https://github.com/lcreid/docker/raw/refs/heads/main/rails-app-sqlite/compose.yml",
|
|
49
|
-
) do |file_contents|
|
|
50
|
-
file_contents.gsub!(
|
|
51
|
-
/jade:rails-app-[0-9]+\.[0-9]+-\w+-\w+$/,
|
|
52
|
-
"jade:rails-app-#{options[:ruby_version] || "3.4"}" \
|
|
53
|
-
"-#{options[:database] || "sqlite"}" \
|
|
54
|
-
"-#{options[:distro_version] || "bookworm"}",
|
|
55
|
-
)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
case Gem::Platform.local.os
|
|
59
|
-
when "linux"
|
|
60
|
-
get_and_save_file("https://github.com/lcreid/docker/raw/refs/heads/main/Linux/compose.override.yml")
|
|
61
|
-
else
|
|
62
|
-
raise Error.new("Not implemented for #{Gem::Platform.local.os}", options[:verbose])
|
|
63
|
-
end
|
|
75
|
+
DockerInitializer.new(**options.transform_keys(&:to_sym).except(:verbose)).get_and_save_compose_files
|
|
64
76
|
end
|
|
65
77
|
|
|
66
|
-
desc "
|
|
78
|
+
desc "initialize_vscode", "Initialize devcontainer.json for vscode"
|
|
67
79
|
def initialize_vscode
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
Dir.mkdir(".vscode") unless Dir.exist?(".vscode")
|
|
73
|
-
[
|
|
74
|
-
"https://github.com/lcreid/jade_systems_toolbox/raw/refs/heads/main/templates/extensions.json",
|
|
75
|
-
"https://github.com/lcreid/jade_systems_toolbox/raw/refs/heads/main/templates/settings.json",
|
|
76
|
-
].each { get_and_save_file(_1, target_directory: File.join(".", ".vscode")) }
|
|
80
|
+
initializer = Vscode.new
|
|
81
|
+
initializer.write_devcontainer_json
|
|
82
|
+
initializer.write_extensions_json
|
|
83
|
+
initializer.write_settings_json
|
|
77
84
|
end
|
|
78
85
|
|
|
79
|
-
desc "open", "Open a page on the services's first port"
|
|
80
|
-
option :service, default: "web"
|
|
81
|
-
option :path, default: "/"
|
|
86
|
+
desc "open", "Open a page on the services's first port or specified port"
|
|
87
|
+
option :service, default: "web", aliases: "-s"
|
|
88
|
+
option :path, default: "/", alias: "-p"
|
|
82
89
|
option :container_port, default: 3000, type: :numeric
|
|
83
90
|
option :protocol, default: "http"
|
|
84
91
|
def open
|
|
@@ -87,14 +94,23 @@ module JadeSystemsToolbox
|
|
|
87
94
|
container_port = options[:container_port]
|
|
88
95
|
protocol = options[:protocol]
|
|
89
96
|
|
|
90
|
-
container_ports = compose_yaml.dig("services",
|
|
97
|
+
container_ports = compose_yaml.dig("services", service, "ports")
|
|
91
98
|
container_port = container_ports&.[](0) || container_port
|
|
92
99
|
path = "/#{path}" if path[0] != "/"
|
|
93
|
-
|
|
100
|
+
url = "#{protocol}://localhost:#{host_port_from_container_port(service:, container_port:)}#{path}"
|
|
101
|
+
if `command -v "open"`
|
|
102
|
+
# Real Unix :-)
|
|
103
|
+
system "open #{url}"
|
|
104
|
+
elsif `command -v "cmd.exe"`
|
|
105
|
+
# WSL because this opens a URL in the browser, which will be on Windows.
|
|
106
|
+
system "cmd.exe /c start #{url}"
|
|
107
|
+
else
|
|
108
|
+
raise ArgumentError, "no suitable command available to open app."
|
|
109
|
+
end
|
|
94
110
|
end
|
|
95
111
|
|
|
96
112
|
desc "port [CONTAINER_PORT]", "Get the host port for the CONTAINER_PORT's container port CONTAINER_PORT"
|
|
97
|
-
option :service, default: "web"
|
|
113
|
+
option :service, default: "web", aliases: "-s"
|
|
98
114
|
def port(container_port = 3000)
|
|
99
115
|
service = options[:service]
|
|
100
116
|
puts host_port_from_container_port(service:, container_port:)
|
|
@@ -113,14 +129,35 @@ module JadeSystemsToolbox
|
|
|
113
129
|
end
|
|
114
130
|
end
|
|
115
131
|
|
|
116
|
-
desc "server [COMMAND]", "Run the server in the container"
|
|
117
|
-
option :
|
|
132
|
+
desc "server [COMMAND] [ARGS]", "Run the server in the container"
|
|
133
|
+
option :env, repeatable: true, default: [], aliases: "-e", banner: "VAR=value"
|
|
134
|
+
option :mapping, type: :boolean, default: true, aliases: "-m"
|
|
135
|
+
option :service, default: "web", aliases: "-s"
|
|
118
136
|
option :work_dir, aliases: "-w"
|
|
119
|
-
def server(command = "bin/dev")
|
|
137
|
+
def server(command = "bin/dev", *args)
|
|
120
138
|
service = options[:service]
|
|
121
139
|
workdir = "-w #{options[:work_dir]} " unless options[:work_dir].nil?
|
|
122
|
-
|
|
140
|
+
environment_variables = options[:env].map { "-e #{_1}" }.join(" ")
|
|
141
|
+
port_map_environment_variables = port_map_for_environment(service) if options[:mapping]
|
|
142
|
+
shell_command = [ command, *args ].join(" ")
|
|
143
|
+
compose_command = [
|
|
144
|
+
"docker compose exec",
|
|
145
|
+
environment_variables,
|
|
146
|
+
port_map_environment_variables,
|
|
147
|
+
workdir,
|
|
148
|
+
service,
|
|
149
|
+
"sh -c",
|
|
150
|
+
"'#{shell_command}'",
|
|
151
|
+
].compact.join(" ")
|
|
152
|
+
|
|
153
|
+
system(compose_command)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
desc "start [COMPOSE_ARGS]", "docker compose up -d (aliased as `up`)"
|
|
157
|
+
def start(*compose_args)
|
|
158
|
+
system(([ "docker compose up -d" ] + compose_args).join(" "))
|
|
123
159
|
end
|
|
160
|
+
map "up" => :start
|
|
124
161
|
|
|
125
162
|
desc "stop", "Stop the service(s) but preserve the container(s)"
|
|
126
163
|
def stop
|
|
@@ -128,15 +165,22 @@ module JadeSystemsToolbox
|
|
|
128
165
|
end
|
|
129
166
|
|
|
130
167
|
desc "terminal", "Run a shell in the container"
|
|
131
|
-
option :
|
|
168
|
+
option :env, repeatable: true, default: [], aliases: "-e", banner: "VAR=value"
|
|
169
|
+
option :mapping, type: :boolean, default: true, aliases: "-m"
|
|
170
|
+
option :service, default: "web", aliases: "-s"
|
|
132
171
|
def terminal
|
|
133
172
|
service = options[:service]
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
173
|
+
environment_variables = options[:env].map { "-e #{_1}" }.join(" ")
|
|
174
|
+
port_map_environment_variables = port_map_for_environment(service) if options[:mapping]
|
|
175
|
+
command = [
|
|
176
|
+
"docker compose exec",
|
|
177
|
+
environment_variables,
|
|
178
|
+
port_map_environment_variables,
|
|
179
|
+
"-it",
|
|
180
|
+
service,
|
|
181
|
+
"'/bin/bash'",
|
|
182
|
+
].join(" ")
|
|
183
|
+
system(command)
|
|
140
184
|
end
|
|
141
185
|
|
|
142
186
|
desc "version", "Show the version number of the tool."
|
|
@@ -148,32 +192,14 @@ module JadeSystemsToolbox
|
|
|
148
192
|
|
|
149
193
|
def compose_yaml = @compose_yaml ||= YAML.load_file(options[:compose_file] || "compose.yml")
|
|
150
194
|
|
|
151
|
-
def get_and_save_file(url, target_directory: nil)
|
|
152
|
-
file_contents =
|
|
195
|
+
def get_and_save_file(url, target_directory: nil, target_file_name: nil)
|
|
196
|
+
file_contents = Http.get_file(url:)
|
|
153
197
|
yield file_contents if block_given?
|
|
154
|
-
file_name = Pathname.new(url).basename.to_s
|
|
198
|
+
file_name = target_file_name || Pathname.new(url).basename.to_s
|
|
155
199
|
file_name = Pathname.new(target_directory) + file_name unless target_directory.nil?
|
|
156
200
|
File.write(file_name, file_contents)
|
|
157
201
|
end
|
|
158
202
|
|
|
159
|
-
def get_file_from_internet(url:, redirects: 10)
|
|
160
|
-
raise Errorl.new("Too many redirects", options[:verbose]) if redirects.zero?
|
|
161
|
-
|
|
162
|
-
uri = URI.parse(url)
|
|
163
|
-
request = Net::HTTP.new(uri.host, uri.port)
|
|
164
|
-
request.use_ssl = true
|
|
165
|
-
response = request.get(uri.path)
|
|
166
|
-
|
|
167
|
-
case response
|
|
168
|
-
when Net::HTTPSuccess
|
|
169
|
-
response.body
|
|
170
|
-
when Net::HTTPRedirection
|
|
171
|
-
get_file_from_internet(redirects: redirects - 1, url: response["location"])
|
|
172
|
-
else
|
|
173
|
-
response.error!
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
|
|
177
203
|
def host_port_from_container_port(container_port:, service: "web")
|
|
178
204
|
ports = container_port.to_s.match(/([0-9]+:){0,1}([0-9]+$)/)
|
|
179
205
|
if !ports[1].nil?
|
|
@@ -183,5 +209,31 @@ module JadeSystemsToolbox
|
|
|
183
209
|
output.match(/[0-9]+$/)
|
|
184
210
|
end
|
|
185
211
|
end
|
|
212
|
+
|
|
213
|
+
def port_map(service)
|
|
214
|
+
service_ports = compose_yaml.dig("services", service, "ports")
|
|
215
|
+
service_ports&.reduce({}) do |acc, port|
|
|
216
|
+
acc[port] = host_port_from_container_port(container_port: port, service:).to_s
|
|
217
|
+
acc
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def port_map_for_environment(service)
|
|
222
|
+
port_map(service).map do |container_port, host_port|
|
|
223
|
+
"-e HOST_PORT_#{container_port}=#{host_port}"
|
|
224
|
+
end.join(" ")
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def handle_argument_error(command, error, args, arity)
|
|
228
|
+
# Check if the error is due to an unknown option or incorrect invocation
|
|
229
|
+
if (error.is_a?(Thor::UnknownArgumentError) || error.message.include?("was called with arguments")) &&
|
|
230
|
+
[ "down" ].include?(command)
|
|
231
|
+
# Return to let Thor proceed instead of raising the error
|
|
232
|
+
nil
|
|
233
|
+
else
|
|
234
|
+
# Fallback to standard Thor behavior for actual code bugs
|
|
235
|
+
super
|
|
236
|
+
end
|
|
237
|
+
end
|
|
186
238
|
end
|
|
187
239
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JadeSystemsToolbox
|
|
4
|
+
class DockerInitializer
|
|
5
|
+
def initialize(compose_file: nil, database: nil, ruby_version: nil, distro_version: nil, end_to_end_tool: nil)
|
|
6
|
+
@end_to_end_tool = end_to_end_tool&.downcase&.strip
|
|
7
|
+
database = database.to_s.downcase.strip
|
|
8
|
+
@database = database unless %w[false none nil ""].include?(database)
|
|
9
|
+
@ruby_version = ruby_version&.downcase&.strip
|
|
10
|
+
@distro_version = distro_version&.downcase&.strip
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def compose_file_path
|
|
14
|
+
base_dir = [ "rails-app", database ].compact.join("-")
|
|
15
|
+
Pathname("compose-files").join(*([ base_dir, end_to_end_tool, "compose.yml" ].compact))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def get_and_save_compose_files
|
|
19
|
+
compose_file = Http.get_file(url: Http.url(path: compose_file_path))
|
|
20
|
+
customize_compose_file!(compose_file)
|
|
21
|
+
File.write("compose.yml", compose_file)
|
|
22
|
+
|
|
23
|
+
case Gem::Platform.local.os
|
|
24
|
+
when "linux"
|
|
25
|
+
compose_override_file = Http.get_file(url: Http.url(path: "compose-files/Linux/compose.override.yml"))
|
|
26
|
+
File.write("compose.override.yml", compose_override_file)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def customize_compose_file!(base_file)
|
|
31
|
+
base_file.gsub!("${RUBY_VERSION:-4.0}", ruby_version) unless ruby_version.nil?
|
|
32
|
+
base_file.gsub!("${DISTRO_VERSION:-trixie}", distro_version) unless distro_version.nil?
|
|
33
|
+
base_file
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
attr_reader :end_to_end_tool
|
|
39
|
+
attr_reader :database
|
|
40
|
+
attr_reader :ruby_version
|
|
41
|
+
attr_reader :distro_version
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JadeSystemsToolbox
|
|
4
|
+
class Http
|
|
5
|
+
class << self
|
|
6
|
+
def url(path:)
|
|
7
|
+
base_url + path.to_s
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def get_file(url:, redirects: 10)
|
|
11
|
+
raise Error.new("Too many redirects", options[:verbose]) if redirects.zero?
|
|
12
|
+
|
|
13
|
+
uri = URI.parse(url)
|
|
14
|
+
request = Net::HTTP.new(uri.host, uri.port)
|
|
15
|
+
request.use_ssl = true
|
|
16
|
+
response = request.get(uri.path)
|
|
17
|
+
|
|
18
|
+
case response
|
|
19
|
+
when Net::HTTPSuccess
|
|
20
|
+
response.body
|
|
21
|
+
when Net::HTTPRedirection
|
|
22
|
+
get_file(redirects: redirects - 1, url: response["location"])
|
|
23
|
+
else
|
|
24
|
+
response.value
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def base_url = "https://github.com/lcreid/jade_systems_toolbox/raw/refs/heads/main/"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module JadeSystemsToolbox
|
|
6
|
+
class Vscode
|
|
7
|
+
def write_settings_json
|
|
8
|
+
target_file = target_directory.join("settings.json")
|
|
9
|
+
settings = if !target_file.exist? || target_file.empty?
|
|
10
|
+
{}
|
|
11
|
+
else
|
|
12
|
+
JSON.load_file(target_file)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
settings["window.title"] = Pathname.pwd.basename
|
|
16
|
+
File.write(target_file, JSON.pretty_generate(settings))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def write_devcontainer_json
|
|
20
|
+
devcontainer_text = Http.get_file(url: Http.url(path: "templates/.devcontainer.json"))
|
|
21
|
+
devcontainer_json = JSON.parse(devcontainer_text, allow_comments: true)
|
|
22
|
+
unless Gem::Platform.local.os == "linux"
|
|
23
|
+
devcontainer_json["dockerComposeFile"] = [ "compose.yml" ]
|
|
24
|
+
end
|
|
25
|
+
Pathname(".devcontainer.json").write(JSON.pretty_generate(devcontainer_json))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def write_extensions_json
|
|
29
|
+
extensions_text = Http.get_file(url: Http.url(path: "templates/extensions.json"))
|
|
30
|
+
target_directory.join("extensions.json").write(extensions_text)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def get_and_write_settings_json
|
|
34
|
+
settings_text = Http.get_file(url: Http.url(path: "templates/settings.json"))
|
|
35
|
+
settings = JSON.parse(settings_text, allow_comments: true)
|
|
36
|
+
settings["window.title"] = Pathname.pwd.basename
|
|
37
|
+
|
|
38
|
+
target_file = target_directory.join("settings.json")
|
|
39
|
+
File.write(target_file, JSON.pretty_generate(settings))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def target_directory
|
|
45
|
+
@target_directory unless @target_directory.nil?
|
|
46
|
+
|
|
47
|
+
@target_directory = Pathname("./.vscode")
|
|
48
|
+
FileUtils.mkdir(@target_directory) unless @target_directory.exist?
|
|
49
|
+
@target_directory
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/jade_systems_toolbox.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "debug"
|
|
4
3
|
require "net/http"
|
|
5
4
|
require "pathname"
|
|
6
5
|
require "thor"
|
|
@@ -8,7 +7,10 @@ require "yaml"
|
|
|
8
7
|
|
|
9
8
|
require_relative "jade_systems_toolbox/version"
|
|
10
9
|
require_relative "jade_systems_toolbox/cli"
|
|
10
|
+
require_relative "jade_systems_toolbox/docker_initializer"
|
|
11
11
|
require_relative "jade_systems_toolbox/error_reporter"
|
|
12
|
+
require_relative "jade_systems_toolbox/http"
|
|
13
|
+
require_relative "jade_systems_toolbox/vscode"
|
|
12
14
|
|
|
13
15
|
module JadeSystemsToolbox
|
|
14
16
|
class Error < StandardError
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
|
2
|
+
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose
|
|
3
|
+
{
|
|
4
|
+
// Update the 'dockerComposeFile' list if you have more compose files or use different names.
|
|
5
|
+
"dockerComposeFile": ["compose.yml", "compose.override.yml"],
|
|
6
|
+
|
|
7
|
+
// The 'service' property is the name of the service for the container that VS Code should
|
|
8
|
+
// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
|
|
9
|
+
"service": "web",
|
|
10
|
+
|
|
11
|
+
// The optional 'workspaceFolder' property is the path VS Code should open by default when
|
|
12
|
+
// connected. This is typically a file mount in .devcontainer/docker-compose.yml
|
|
13
|
+
"workspaceFolder": "/home/dev/app",
|
|
14
|
+
// "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}"
|
|
15
|
+
|
|
16
|
+
// Features to add to the dev container. More info: https://containers.dev/features.
|
|
17
|
+
// "features": {},
|
|
18
|
+
|
|
19
|
+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
|
20
|
+
// "forwardPorts": [],
|
|
21
|
+
|
|
22
|
+
// Uncomment the next line if you want start specific services in your Docker Compose config.
|
|
23
|
+
// "runServices": [],
|
|
24
|
+
|
|
25
|
+
// Uncomment the next line if you want to keep your containers running after VS Code shuts down.
|
|
26
|
+
"shutdownAction": "none"
|
|
27
|
+
|
|
28
|
+
// Uncomment the next line to run commands after the container is created.
|
|
29
|
+
// "postCreateCommand": "cat /etc/os-release",
|
|
30
|
+
|
|
31
|
+
// Configure tool-specific properties.
|
|
32
|
+
// "customizations": {},
|
|
33
|
+
|
|
34
|
+
// Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root.
|
|
35
|
+
// "remoteUser": "devcontainer"
|
|
36
|
+
}
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jade_systems_toolbox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Larry Reid
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-11-14 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: thor
|
|
@@ -23,6 +24,7 @@ dependencies:
|
|
|
23
24
|
- - "~>"
|
|
24
25
|
- !ruby/object:Gem::Version
|
|
25
26
|
version: '1.3'
|
|
27
|
+
description:
|
|
26
28
|
email:
|
|
27
29
|
- lcreid@jadesystems.ca
|
|
28
30
|
executables:
|
|
@@ -41,9 +43,13 @@ files:
|
|
|
41
43
|
- exe/tool
|
|
42
44
|
- lib/jade_systems_toolbox.rb
|
|
43
45
|
- lib/jade_systems_toolbox/cli.rb
|
|
46
|
+
- lib/jade_systems_toolbox/docker_initializer.rb
|
|
44
47
|
- lib/jade_systems_toolbox/error_reporter.rb
|
|
48
|
+
- lib/jade_systems_toolbox/http.rb
|
|
45
49
|
- lib/jade_systems_toolbox/version.rb
|
|
50
|
+
- lib/jade_systems_toolbox/vscode.rb
|
|
46
51
|
- sig/jade_systems_toolbox.rbs
|
|
52
|
+
- templates/.devcontainer.json
|
|
47
53
|
- templates/extensions.json
|
|
48
54
|
- templates/settings.json
|
|
49
55
|
homepage: https://github.com/lcreid/jade_systems_toolbox
|
|
@@ -53,6 +59,7 @@ metadata:
|
|
|
53
59
|
homepage_uri: https://github.com/lcreid/jade_systems_toolbox
|
|
54
60
|
source_code_uri: https://github.com/lcreid/jade_systems_toolbox
|
|
55
61
|
changelog_uri: https://github.com/lcreid/jade_systems_toolbox/CHANGELOG.nd
|
|
62
|
+
post_install_message:
|
|
56
63
|
rdoc_options: []
|
|
57
64
|
require_paths:
|
|
58
65
|
- lib
|
|
@@ -60,14 +67,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
60
67
|
requirements:
|
|
61
68
|
- - ">="
|
|
62
69
|
- !ruby/object:Gem::Version
|
|
63
|
-
version: '3.
|
|
70
|
+
version: '3.3'
|
|
64
71
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
72
|
requirements:
|
|
66
73
|
- - ">="
|
|
67
74
|
- !ruby/object:Gem::Version
|
|
68
75
|
version: '0'
|
|
69
76
|
requirements: []
|
|
70
|
-
rubygems_version:
|
|
77
|
+
rubygems_version: 3.5.22
|
|
78
|
+
signing_key:
|
|
71
79
|
specification_version: 4
|
|
72
80
|
summary: A collection of command line commands to support development.
|
|
73
81
|
test_files: []
|