odysseus-cli 0.3.0 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 286c6f613a97b1f0fe05e0fbe7c32134743f548a54963a3f118d8291ccebc792
4
- data.tar.gz: 3d31e2e4a8d0a6bd64eb20d549d96b49a00885474a7c9fbd4467e9394bd254a0
3
+ metadata.gz: 1a6fb5fd56accf0b7051db85619b6e7c9303b9a46d04466e5c77e863cce23b2b
4
+ data.tar.gz: e8eca22a11595c8febbe6649563c8c7bcfd79075c4e12c8c5192c0a39db53804
5
5
  SHA512:
6
- metadata.gz: 1a9f282b7f6c4380c28011bba65ed280ae791bbd27317aaf063e237a41d3a69ccd8de64dd24969f1664636b841897965070d2230a1949ce906b0b42cc98eed81
7
- data.tar.gz: 33dfa6160b2db4ff12b1a31c6da6abaf22a8852d59b002cd82c029a231a00306e9df1cbeeb4727c615519dc97fa9ec3d62b3bab6a6732c52f9d71e9c405e1607
6
+ metadata.gz: a32d16273041d33d8edd3c9f7a58c43e174c1327f6528756531db4f90b50d02841df5a95f5fb56f9b0a38f8742f13d617013f45564e94605e06a30bb4ec64177
7
+ data.tar.gz: d2859b817e910833e116a135a775d7603102db90bb4ecbe6841c3dc1085f245e61060e09f78de3723629ace393e09ee40163e86520b28dab43a1cd3f5257f76a
data/CHANGELOG.md ADDED
@@ -0,0 +1,332 @@
1
+ # Changelog
2
+
3
+ All notable changes to odysseus-cli are documented here.
4
+
5
+ Entries for 0.3.0 and earlier were reconstructed from git history and the built
6
+ gem artifacts, so they are summaries rather than contemporaneous notes.
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Changed
11
+
12
+ - `cleanup`'s documentation now describes what the command does. It was
13
+ "Clean up old containers and optionally prune images" in both the README and
14
+ `--help`; it stops and force-removes every container for the service on that
15
+ server -- every role and every dependency, databases included, not only old
16
+ ones and not sparing the container serving traffic -- then removes the
17
+ service's Caddy routes and, if no other service is left behind the proxy,
18
+ removes the shared `odysseus-caddy` container too. No behaviour changed. The
19
+ name still undersells it; see TODO.md.
20
+
21
+ ## [0.9.0] - 2026-08-19
22
+
23
+ ### Fixed
24
+
25
+ - `setup` names the `--as` flag when the bootstrap identity cannot
26
+ authenticate. The default identity is a guess — right on a stock Ubuntu
27
+ cloud image, wrong on anything else — and the failure was a bare "SSH
28
+ authentication failed", with nothing to suggest a flag existed that would
29
+ fix it. A host that is merely unreachable still gets no `--as` advice.
30
+ - `--debug` (and `ODYSSEUS_DEBUG=1`) reaches the SSH layer, not only the UI.
31
+ It was read and passed to the UI, but the connection builders never passed
32
+ `verbose:` to `SSH.new`, so the flag whose purpose is showing what was sent
33
+ to the host showed nothing for `setup`, `doctor`, `status`, `containers` or
34
+ `logs`. `setup` accepts `-v` as well.
35
+
36
+ ### Added
37
+ - `odysseus setup`, which prepares every host in the config so odysseus can
38
+ deploy to it as a non-root user: creates the user `ssh.user` names, adds
39
+ it to the `docker` group, installs your public key, installs Docker
40
+ itself if the host doesn't have it, and creates its state directory.
41
+ Connects as `--as USER`, default `ubuntu` — the user Ubuntu's LTS cloud
42
+ images ship with passwordless sudo already configured; `--as root` needs
43
+ no sudo. It reads no new configuration keys: the user, keys and hosts all
44
+ come from the existing `ssh.user`, `ssh.keys` and `servers.*.hosts`, with
45
+ `--key PATH` (repeatable) to override the key source. `setup` no longer
46
+ refuses a host without Docker — if `docker info` doesn't answer, it
47
+ installs Docker from Docker's own apt repository and checks again, and
48
+ only fails the step if the daemon still doesn't answer afterward — and it
49
+ still refuses anything other than Ubuntu 24.04 or 26.04 by name. It
50
+ reports what it changed separately from what was already correct, and
51
+ finishes by reconnecting as the new user to prove the host actually works
52
+ before reporting success.
53
+
54
+ ## [0.8.0] - 2026-08-17
55
+
56
+ ### Changed
57
+ - Requires odysseus-core `~> 0.8.0`. The dependency was `~> 0.7.0`, which
58
+ excludes 0.8.0 outright, so this is not a tightening: without it the two gems
59
+ cannot resolve together. `odysseus doctor` also calls
60
+ `Odysseus::HostVerifier` and `Executor#host_roles`, neither available in
61
+ 0.7.0.
62
+
63
+ ### Added
64
+ - `odysseus doctor`, a read-only diagnosis of every host in the config,
65
+ connecting as the user `ssh.user` names rather than root. It reports
66
+ distro, docker reachability, docker group membership, state-directory
67
+ writability and deploy-log location for each host, via
68
+ `Odysseus::HostVerifier` (odysseus-core). An unsupported distro is a
69
+ warning rather than a failure; only a failing check sets a non-zero exit.
70
+ A host whose check raises — a dropped connection, say — is reported and
71
+ the survey continues to the rest. `doctor` changes nothing on the host.
72
+
73
+ ## [0.7.0] - 2026-08-16
74
+
75
+ Read the exit-code changes below before upgrading anything that scripts these
76
+ commands. `logs` now exits non-zero when it finds no container, where it used to
77
+ report the problem and exit 0, and `app shell`/`console` exit with the remote
78
+ command's status instead of always 0. A cron or CI job that treated either as
79
+ "succeeded" will start noticing failures — which is the point, but it is a
80
+ change in what those jobs see.
81
+
82
+ ### Changed
83
+ - Requires odysseus-core `~> 0.7.0`. The dependency was `~> 0.6.0`, which
84
+ excludes 0.7.0 outright, so this is not a tightening: without it the two gems
85
+ cannot resolve together. These commands also call `Core::Environment` and
86
+ `Docker::Client#with_env_file`, neither of which exists in 0.6.0.
87
+ - `bin/odysseus`'s dispatch table no longer lists `dependency`, `app` and
88
+ `secrets`. Their entries named methods the CLI has never had
89
+ (`dependency_dispatch`, `app_dispatch`, `secrets_dispatch`); the subcommand
90
+ guards intercept those verbs first, so nothing changes today, but the entries
91
+ would have turned any reordering of a guard into a `NoMethodError` backtrace.
92
+ The suite now runs every verb the help lists.
93
+
94
+ ### Fixed
95
+ - `odysseus app exec|shell|console` now inject `env.secret` as well as
96
+ `env.clear`. They injected the clear values alone, so the README's own
97
+ example — `odysseus app exec web1 --command "rails db:migrate"` — started a
98
+ container with no `DATABASE_URL` while the container deployed seconds earlier
99
+ had one. Both orchestrators had always injected both; these three never did.
100
+ The environment is now built by the same `Core::Environment` the deploy paths
101
+ use, so a secret resolves from the encrypted file when one is configured and
102
+ from the host's own environment otherwise, exactly as a deploy resolves it.
103
+ - A relative `secrets_file` is resolved against the directory holding the
104
+ `deploy.yml` these commands were pointed at, not the working directory, which
105
+ is the rule deploys already followed.
106
+ - `odysseus app shell|console` pass the environment to docker with `--env-file`
107
+ instead of `-e KEY=VALUE`. The values were in the command string these
108
+ commands run over ssh, so `ps` on the deploy target showed them to every user
109
+ on the box; now only the file's path is. The file is `0600`, is held open for
110
+ the whole session and is removed when the session ends, however it ends —
111
+ including when the ssh connection it was written over has died while the
112
+ session sat idle, which is removed over a fresh connection. Two cases still
113
+ leave it on the host: the `odysseus` process being killed outright
114
+ (`SIGKILL`, or the machine going down), where no cleanup can run at all, and
115
+ a host that is unreachable when the session ends, where the removal has
116
+ nowhere to go. The file is `0600` in `/var/lib/odysseus/env`, which is `0700`,
117
+ so no other user on the box can read it, but nothing comes back for it.
118
+ `app exec` reaches the same place through `run_once`, which writes an env
119
+ file of its own — see odysseus-core's changelog.
120
+ - `odysseus dependency exec|shell` are unchanged: they `docker exec` into an
121
+ already-running dependency, which carries the environment it was booted with.
122
+ - `odysseus app exec|shell|console` now take `--role` (default `web`) and look
123
+ the container up by the label that role actually carries. They asked for the
124
+ bare service name, which only the web role wears: on a jobs host they
125
+ reported `No running container for myapp` while `myapp-jobs` containers were
126
+ running, and for a service with no web role at all they could not work on any
127
+ host, with no workaround. The `app` parser had no `--role` either, so naming
128
+ one raised an `OptionParser::InvalidOption` backtrace.
129
+ - The not-found message from those commands now names the role, the
130
+ `odysseus.service` label it searched for and the `--role` option, and lists
131
+ the roles in the config. It does not search other roles: running your command
132
+ against a role you did not name would be worse than being told what to type.
133
+ - `odysseus logs` gives that same message. A mistyped `--role` — `odysseus logs
134
+ w1 --role jbos` — got `No containers found for myapp-jbos on w1 (stopped ones
135
+ included)`, naming a label the reader never typed and no way to find the one
136
+ they wanted. Both commands now share the message rather than keeping two that
137
+ can drift. `odysseus dependency logs` gets the label it searched for too, but
138
+ not the `--role` advice: a dependency is chosen with `--name`.
139
+ - `odysseus logs` and `odysseus dependency logs` read stopped containers as
140
+ well as running ones. They asked `docker ps` without `-a`, so the container
141
+ that had just exited — the one you want the logs of — was invisible, and they
142
+ reported `No running containers found` and exited **0** while `docker logs`
143
+ on that container would have worked. Deploys keep the previous two
144
+ containers, so this was routine rather than an edge case.
145
+ - Those two commands now exit non-zero when there is no container at all: a
146
+ request for logs that produced none is a failed request, not a success. When
147
+ the only match is stopped they say so, and name the container, rather than
148
+ streaming a dead container's logs and leaving you to wonder why it ends.
149
+ - Both of those messages go to **stderr**. `odysseus logs web1 > app.log` is
150
+ the command most likely to be redirected or piped into something that parses
151
+ what it gets, and a line about the logs does not belong inside them. The
152
+ notice still reaches the terminal of whoever ran the command. Every other
153
+ command writes where it always did.
154
+ - `odysseus app shell|console` and `odysseus dependency shell` now exit
155
+ non-zero when the session fails. They discarded `system`'s return value, so a
156
+ refused ssh, a missing image or a failed `docker run` all reported success.
157
+ - The same three quote what they put in the command they run. Values were
158
+ interpolated raw into a string that passes through two shells, so ordinary
159
+ `env.clear` values broke them: a value containing a space made docker read
160
+ the wrong token as the image name, and an apostrophe (`SMTP_FROM: "Bob's
161
+ App"`) unbalanced the quoting — an odd number left `sh: unexpected EOF` and
162
+ nothing running (reported as success, per the bug above), an even number
163
+ rebalanced the quotes and ran the text between them through the *local*
164
+ shell. An SSH key path containing a space failed the same way.
165
+ - `odysseus app console --cmd` is split into words the way a shell would, so
166
+ `--cmd "rails c"` still reaches docker as two arguments, and a `--cmd` whose
167
+ own quoting cannot be read is reported instead of being passed on.
168
+ - `odysseus app shell|console` print a header before handing the terminal over.
169
+ They printed nothing at all: `odysseus app shell dedalus-prod` answered with
170
+ `/app $` and no way to tell which host you had reached, which role, or which
171
+ build you were looking at. `app exec` has had a header from the start. The
172
+ new one names the server, the role, the image that is serving and the command
173
+ the container runs, in the same shape as `app exec`'s.
174
+ - It also says the thing a prompt inside a container invites you to assume the
175
+ other way round: this is a **new container** started from the serving image,
176
+ not an attach to the container taking traffic. Nothing done in it reaches the
177
+ running app and all of it goes when the session ends. `odysseus dependency
178
+ shell` is deliberately not given the same line — it `docker exec`s into the
179
+ running dependency, where the opposite is true.
180
+ - That header goes to **stderr**. `odysseus app console web1 --cmd "rails
181
+ runner 'puts Thing.count'" > count` is a reasonable way to read a value out
182
+ of a deployment, and a header inside that file would be a bug: stdout carries
183
+ what the session itself produced and nothing else. `app exec`'s header is
184
+ unchanged, on stdout, where the output of its `run_once` already is.
185
+
186
+ ## [0.6.0] - 2026-08-15
187
+
188
+ ### Changed
189
+ - `odysseus validate` now loads `plugins:`/`sails:` before checking the rest
190
+ of the config, so it catches a plugin gem that is not installed instead of
191
+ only discovering the gap at deploy time. It will fail on a machine that
192
+ does not have the gem, where it passed before. See odysseus-core's
193
+ changelog for the loading mechanism itself.
194
+ - Requires odysseus-core `~> 0.6.0`. The dependency was `~> 0.5.0`, which
195
+ excludes 0.6.0 outright, so the two gems could not resolve together at all.
196
+ - The README documents dynamic ASG hosts again, now that `plugins:` makes them
197
+ reachable. The example it previously carried could not have parsed: it showed
198
+ an `aws:` role with no `hosts:` key, which every role requires.
199
+
200
+ ## [0.5.0] - 2026-08-13
201
+
202
+ ### Changed
203
+ - Requires odysseus-core `~> 0.5.0`. The previous `~> 0.4.4` constraint
204
+ excludes 0.5.0 outright, so this is not a tightening but a necessary move:
205
+ without it the two gems cannot resolve together at all.
206
+ - `odysseus deploy` now prunes old images on each host, keeping the newest
207
+ `retain_versions` (default 5). See odysseus-core's changelog for what is
208
+ protected from removal.
209
+
210
+ ## [0.4.4] - 2026-08-13
211
+
212
+ ### Changed
213
+ - Requires odysseus-core `~> 0.4.4`. The dependency was `~> 0.4.3`, which
214
+ allowed installing a core whose `Executor` still named its six methods
215
+ `deploy_accessory`, `boot_accessories` and so on — all of which the dependency
216
+ commands call under their new names, so they would have failed with a
217
+ NoMethodError rather than a resolvable error.
218
+ - `odysseus accessory` is now `odysseus dependency`, with `dep` accepted as
219
+ shorthand. The old verb still works and prints a notice naming the
220
+ replacement, because a silent alias never gets migrated away from; it will be
221
+ removed in a later release. The `accessories:` key in deploy.yml is likewise
222
+ now `dependencies:`, with the old key still accepted — see odysseus-core's
223
+ changelog for why nothing on a host changes when you rename it.
224
+ - Help text, subcommand output and the `Dependency name required` error read
225
+ "dependency" throughout.
226
+
227
+ ## [0.4.3] - 2026-08-13
228
+
229
+ ### Added
230
+ - `odysseus rollback [VERSION]`, returning every role on every host to a
231
+ previously deployed version. With no VERSION, the target is the most recent
232
+ version in the hosts' deploy logs that is not already serving and whose image
233
+ is still present everywhere. Refuses, changing nothing, when any host lacks
234
+ the image.
235
+ - `odysseus rollback --list`, showing per host: every version deployed, when,
236
+ by whom, from which commit, whether the image is still present, and what is
237
+ serving. Reads only the hosts, so it works without a git repository.
238
+
239
+ ### Changed
240
+ - Requires odysseus-core `~> 0.4.3`. The dependency was `~> 0.4.2`, which
241
+ allowed installing a core without `Executor#rollback_plan`, `#rollback_all`
242
+ or `#version_survey` — all of which `rollback` calls, so the command would
243
+ have failed with a NoMethodError rather than a resolvable error.
244
+
245
+ ### Fixed
246
+ - `odysseus accessory status` now works. It has raised `NoMethodError` since
247
+ before the subcommand shipped in 0.2.0; see odysseus-core's changelog for the
248
+ root cause and fix.
249
+
250
+ ### Internal
251
+ - Rollback commands moved out of the main `CLI` class into
252
+ `Odysseus::CLI::RollbackCommands`, to keep the class under its existing size
253
+ limit without changing its public API.
254
+
255
+ ## [0.4.2] - 2026-08-13
256
+
257
+ ### Changed
258
+ - `deploy`, `build` and `pussh` no longer default `--image` to the `latest`
259
+ tag; the tag now defaults to the git commit being deployed, and is required
260
+ outside a clean git repository.
261
+ - `status` reports the version, ref and deploy time of each container.
262
+ - `app exec`, `app shell` and `app console` run the version that is currently
263
+ serving instead of `:latest`.
264
+ - Requires odysseus-core `~> 0.4.2`. The dependency was `~> 0.4`, which allowed
265
+ installing a core without `Executor#deploy_version` or `Docker::Labels` — both
266
+ of which these commands now call, so `deploy` would have failed with a
267
+ NoMethodError rather than a resolvable error.
268
+
269
+ ## [0.4.1] - 2026-08-12
270
+
271
+ Released in lockstep with odysseus-core 0.4.1, which fixes the Caddy TLS
272
+ policy update. No changes to the CLI itself.
273
+
274
+ ## [0.4.0] - 2026-08-12
275
+
276
+ ### Added
277
+ - `odysseus version` and `--version`, reporting the CLI, odysseus-core and ruby
278
+ versions. Answered before any config is loaded, so it works without a
279
+ deploy.yml or a reachable server.
280
+ - `Odysseus::CLI::VERSION`, so the gem version has one source of truth instead
281
+ of being hardcoded in the gemspec.
282
+ - A test suite: RSpec, `.rspec` and a `rake` default task. Argument dispatch and
283
+ exit codes are covered by running the real executable in a subprocess, the
284
+ commands are unit-tested against a doubled executor, and the redaction of
285
+ secrets from streamed output is pinned.
286
+ - RuboCop, sharing odysseus-core's configuration.
287
+
288
+ ### Changed
289
+ - Requires odysseus-core `~> 0.4`. The dependency was `~> 0.2`, which allowed
290
+ installing a core old enough to lack the deploy fixes the CLI relies on.
291
+ - Requires Ruby >= 3.2.0, matching odysseus-core. The gemspec asked for >= 3.0,
292
+ which could not have worked.
293
+ - Licensed under MIT. The gemspec previously said LGPL-3.0-only while the README
294
+ said MIT.
295
+ - `CLEAN_MESSAGES` is a `private_constant`; it sat after a `private` modifier,
296
+ which does nothing for constants.
297
+ - Development dependencies live in the Gemfile only, as in odysseus-core; the
298
+ gemspec declared rspec and pry-byebug a second time.
299
+
300
+ ### Fixed
301
+ - The gem now ships its license file. `spec.files` looked for `LICENSE` while
302
+ the file is `LICENSE.txt`, so published gems contained no license text.
303
+
304
+ ### Removed
305
+ - The `ratatui_ruby` dependency. Nothing in the CLI required or referenced it —
306
+ it pulled a native extension into every install for nothing.
307
+ - Documentation for Charm mode (`--charm`, `ODYSSEUS_CHARM=1`, `gum`), removed
308
+ from the code in 0.3.0 but left in the README, and for AWS Auto Scaling Group
309
+ hosts, which moved to a sail gem nothing currently loads.
310
+
311
+ ## [0.3.0] - 2026-04-04
312
+
313
+ ### Changed
314
+ - Rewrote terminal output as numbered steps with animated spinners resolving to
315
+ ✓/✗, rendered by `CLI::UI`, replacing the gum-backed Charm mode. `--debug`
316
+ (or `ODYSSEUS_DEBUG=1`) switches to verbose plain text.
317
+ - Secret values are redacted from streamed output via `RedactingIO`.
318
+
319
+ ## [0.2.0] - 2025-12-30
320
+
321
+ ### Added
322
+ - Charm TUI mode (`--charm`, `ODYSSEUS_CHARM=1`) built on gum, for styled
323
+ headers, spinners, tables and confirmations. Superseded in 0.3.0.
324
+ - `secrets` subcommands: generate-key, encrypt, decrypt, edit.
325
+ - `accessory` subcommands: boot, boot-all, remove, restart, upgrade, status,
326
+ logs, exec, shell.
327
+ - `pussh` command for pushing images to hosts over SSH without a registry.
328
+
329
+ ## [0.1.0] - 2025-12-21
330
+
331
+ - Initial release: deploy, build, status, containers, logs, cleanup, validate,
332
+ and the `app` subcommands.
data/LICENSE.txt ADDED
@@ -0,0 +1,26 @@
1
+ MIT License
2
+
3
+ Copyright (c) Imfiny SAS / Wa Systems SAS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ Odysseus Pro and Odysseus Enterprise are distributed under separate
26
+ commercial terms.