odysseus-cli 0.3.0 → 0.10.0

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