Releases: meloncafe/dctl
Release list
v0.6.0 — parsing fix + validate hardening
[0.6.0] - 2026-06-13
Review-driven fixes and hardening. No breaking changes for well-formed
registries.
Fixed
get_fieldcorrupted values containing#. Inline-comment stripping
removed everything from the first#, sopost_up = echo "#done"became
echo "and a URL likehttp://x/y#fraglost its fragment. Comment
stripping is now quote-aware: a#starts a comment only when it is outside
quotes and preceded by whitespace. A#inside quotes, attached to a
word, or at the start of a value is preserved. Quote a value if you need a
literal " #".TAILis validated up front. A non-numericTAIL(e.g.TAIL=abc) now
fails with a clear message instead of producing a cryptic docker error later.
Added
validateflags duplicate[section]names instead of silently using
the first and ignoring the rest.validatewarns on an over-permissive registry. Because the registry can
hold hook command strings, a file readable by group/other is flagged with a
chmod 600suggestion.- CI now lints
completion.bashalongsidedctl.
v0.5.1 — clean self-update output
[0.5.1] - 2026-06-13
Patch. No breaking changes.
Changed
self-updateoutput is now a short progress summary instead of git's raw
fetch/merge log. It printschecking for updates…,applying N new commit(s)…, andupdated to dctl <version>— no object counting, no
From github.com…line, no fast-forward diffstat, and none ofinstall.sh's
routine output. The installer's output is captured and shown only if it
fails.already up to datestays a one-liner with the version.
v0.5.0 — version, update check, completion
[0.5.0] - 2026-06-13
Feature pass. No breaking changes.
Added
versioncommand (aliases--version/-v) — prints the dctl version,
which is now also shown in thehelpheader. The version is a constant in
the script, so it prints instantly with no git or network access.- Quiet update check —
versionandself-updatedo a short-timeout
git fetchand report how many commits the upstream is ahead. It runs only
for those two commands, so everyday commands (logs,restart, …) do no
network I/O. The check stays completely silent on any failure — offline, an
intranet with no route to GitHub, no git, or not a checkout — so it never
hangs or adds noise. - Shell completion (
completion.bash, bash + zsh) — completes subcommands,
global flags, and registered service names (dctl <Tab>,dctl restart <Tab>).install.shnow sources it from your shell rc (idempotent), so it
activates after the nextinstall.shrun (e.g. viaself-update) and a new
shell.
v0.4.1 — self-update divergence fix
[0.4.1] - 2026-06-13
Patch. No breaking changes.
Fixed
self-updatenow diagnoses why a fast-forward can't happen. It used to
rungit pull --ff-onlyand, on failure, always blamed local commits or
changes — misleading after an upstream force-push (e.g. a squash), which left
a checkout stuck on a raw "Not possible to fast-forward" git error. It now
fetches and classifies the state, then prints the right recovery:
up-to-date (no-op), behind (fast-forwards), uncommitted changes
(git checkout -- .), local commits ahead (git reset --hard <upstream>),
or diverged history from a force-push (git reset --hard <upstream>, noting
the registry in~/.config/dctlis untouched).
v0.4.0 — feature expansion
[0.4.0] - 2026-06-13
Feature expansion. No breaking changes.
Added
- Multi-service commands — pass several service names
(dctl restart web db api) or--allto act on every registered service.
Services run in turn; one failure neither aborts the batch nor leaks state
(each runs in an isolated subshell), and a summary reports any failures with
a non-zero exit.exec,logs, andconfigremain single-service. --dry-run/-n— print the compose plan and hooks (location, files,
arguments) without executing anything,pruneincluded. Combines with
multi-service to preview a whole batch.
Changed
- Command execution was extracted into
dispatch_command()so it can run
per-service. Single-service and current-directory behavior is unchanged. - Multi-service
restartskips the trailinglogs -f(following the first
service's logs would block the rest); single-servicerestartstill follows.
v0.3.0 — convenience
[0.3.0] - 2026-06-13
Convenience pass. No breaking changes.
Added
validate(aliasdoctor) — sanity-checks the registry: every service
has apath, local paths and listed compose files exist, andnodealiases
look defined in~/.ssh/config. Remote path/file existence is not checked
(would need an ssh round-trip). Exits non-zero if any problem is found.- Color output and global flags —
ok/warn/errmessages are
colored; color auto-disables whenNO_COLORis set,--no-coloris passed,
or stderr is not a terminal.--quiet/-qsilences info/ok/warn (errors
are always shown). Both flags may appear anywhere on the command line.
Changed
editnow tries$EDITOR,$VISUAL,nano,vi,vimin order, and
if none is available prints the registry path instead of failing silently.self-updateexplains a failed fast-forward (local commits/changes) and
how to recover, instead of surfacing a raw git error.
v0.2.0 — reliability & tests
[0.2.0] - 2026-06-13
Reliability and testability pass. No breaking changes.
Fixed
- Remote argument quoting —
run_compose's ssh path built the command with
a bare"$*", so an argument likesh -c "pg_dump | gzip"split at the pipe
on the remote shell (the pipe became a separate remote command — a data-loss
risk), and spaces within an argument became separate words. Arguments and the
remotecdtarget are now serialized withprintf '%q'. Local execution was
already correct and is unchanged. - Removed a no-op
TAIL=...env assignment on therestartlogs line
(shellcheck SC2097/SC2098); the trailing${TAIL:-20}already applied the
default, so behavior is unchanged.
Added
- Test suite (bats) — unit tests for the registry parser (
get_field,
list_services), target resolution (resolve), compose-file assembly, and
remote ssh argument serialization. 22 tests. - CI — GitHub Actions runs shellcheck and the bats suite on every push and
pull request.
Changed
- Internal refactor — all logic moved into functions;
main()runs only
when the script is executed directly (sourcing exposes functions for tests
without side effects). No change to the command-line behavior.
v0.1.0
First public release of dctl, a unified docker compose controller.
Resolve services by name from a central registry, drive them from the current directory or by name, and reach remote nodes over ssh — with per-service hooks and multi compose-file support. Replaces the per-directory logs.sh / restart.sh sprawl with one command.
Highlights
- Name-based control —
dctl restart webfrom anywhere, nocdneeded - Remote over ssh —
node = <ssh-host>runs compose on another machine via your~/.ssh/config - Per-service hooks —
pre_up/post_up/pre_down/post_down - Multiple compose files —
files = a.yml b.yml self-update— updates the scripts only; your registry is never touched- Failed
uprolls back — no silently half-started stacks - gh-free public install —
curl -fsSL .../install-public.sh | bash
Security
Hook values are executed verbatim (locally and over ssh). Treat the registry like a script you run as yourself — see the README Security section.
Full changelog: https://github.com/meloncafe/dctl/blob/main/CHANGELOG.md