Releases: hampel/wback
Releases · hampel/wback
Release list
7.5.0
Needs PHP 8.3 or newer. Download both assets, keep the binary
named wback-7.5.0 so the checksum matches, and verify with
sha256sum --ignore-missing -c SHA256SUMS before installing it.
See the README for the .env it then needs.
Added
app:validate --unattended, for a run nobody is watching. Two of the checks
are only worth their cost when someone looks at where the message landed — the
sweep that writes a record at every log level, and the run summary test post —
and a deploy gate fires both into an operations channel with nobody having
asked. The flag suppresses those two and nothing else: thercloneremote
checks still go out, because a remote that has stopped responding is what an
automated gate exists to surface. Both report as skips rather than
disappearing, and the flag is never the default — forgetting it costs some
channel noise you can delete, whereas defaulting it on would cost every future
run its proof of delivery, silently.- The logging section now says how many records the Slack channel should have
taken, and at which levels —posted 3 records at critical and above: critical, alert, emergency. The sweep is the only thing that proves the webhook URL and
LOG_SLACK_LEVELare both right, since neither can be checked from the sending
end, and that only works if you know what number to expect. It also reports a
slack channel sitting in the stack with no webhook to post to, which previously
looked identical to a working one.
7.4.2
Needs PHP 8.3 or newer. Download both assets, keep the binary
named wback-7.4.2 so the checksum matches, and verify with
sha256sum --ignore-missing -c SHA256SUMS before installing it.
See the README for the .env it then needs.
Added
- Continuous integration, and with it an automated release.
.github/workflows/ci.yml
runs the test suite and compiles the binary on every push and pull request; pushing
a tag builds the artefact, generatesSHA256SUMSand publishes the GitHub release
with that version's changelog section as its notes. The asset names are unchanged —
wback-<version>andSHA256SUMS— so the documented install and the pyinfra
checksum pin both keep working. The README carries the run status as a badge. - The two release traps are now structural rather than remembered. A tag-triggered
build cannot compile a stalegit describe, and the release job refuses to publish
a binary whose--versiondoes not equal the tag; the build runscomposer build
from a clean checkout, so a fat artefact like 7.0.0–7.4.0's cannot be produced by
forgetting a step. The compiled binary is also smoke-tested — it runs, reports its
own version, and exits non-zero on a mistyped command, which is the one behaviour
the suite cannot check on the artefact that actually ships.
Changed
app:validatedraws its six group headings throughhampel/console-report's
newcheckSection()(2.1.0) rather than the app's ownsection(). They move
to the two-column margin, so a heading now lines up with the[ ok ]markers
beneath it instead of hanging to their left, and the rule under it goes. The
check rows themselves are unchanged.- Backup runs keep the ruled cyan heading:
section()stays inLogsToConsole
forcronand the per-site headings, where a rule across a scrolling run log
is doing a different job to a heading over a report you read top to bottom.
Fixed
- An unrecognised log level passed to
log()now renders at normal verbosity as
intended. The fallback was the string'warning'where aVERBOSITY_*integer
belongs, whichline()does not recognise and quietly replaces with whatever
verbosity was last set. Latent — every current caller passes a level the map
knows.
wback 7.4.1
[7.4.1] - 2026-08-25
Fixed
- The released binary no longer carries the development dependencies.
app:build
never runs Composer andbox.jsontakesvendor/wholesale, so building from a
dev checkout compiled Pint, PHPUnit, Pest and Mockery into the artefact — Pint
alone was 21 MB of it. The download drops from 29 MB to 6 MB, and a
production server stops being handed a code formatter and a test framework it
will never run. No behaviour changes: same code, same command strings, same
exit codes. - 7.0.0 through 7.4.0 are all affected and are left as published, since their
checksums are pinned and a release whose bytes change under a fixed version is
the thing checksums exist to prevent. Upgrade to get the smaller one.
Added
composer build, which installs--no-dev, compiles, restores the dev
dependencies, and then fails iflaravel/pintis still findable in the
artefact. That last grep is the whole guard — nothing else noticed for five
releases.
wback 7.4.0
[7.4.0] - 2026-08-25
Added
app:validatenow warns when a site's file source exists but is empty. The
nightly refuses an empty source, so validate said[ ok ]about a site that
was guaranteed to fail —test.hampelgroup.netwas green in validate for as
long as it existed, and the 03:17 run is what found it. What validate warns
about mirrors what the stage refuses, which is how the sync check beside it
already worked; files simply never got the same treatment. It is a warning and
not a failure, so the exit code is unchanged and a deploy gating on
app:validatecannot start failing because of it.
wback 7.3.1
[7.3.1] - 2026-08-25
Fixed
app:validateno longer stops at the first check whose command will not start.
A command that cannot be spawned at all — an unreadable working directory does
this to every one of them — is now a failed check like any other, so the
remaining binaries, and the paths, sites, remotes, logging and summary after
them, are still reported. This happened on ap1: one run ended atmysqldump
and looked at nothing else, which is the worst moment to stop talking for a
command whose whole job is to say what is wrong.- A check that cannot start now reports the cause rather than the first line of
the exception.proc_open(): posix_spawn() failed: Permission denied (working directory: /root)says what to fix;The command "…" failed.repeats the
check's own label. The whole message still goes to the log, with the check and
the command as context.
Changed
- A file backup of an empty source directory now fails as an empty source
directory, rather than aszipexit code 12 and "Nothing to do!". An
unexpectedly empty docroot is worth failing over — it is what a half-finished
migration looks like at 03:17 — but it should say so in the site's terms and
name the site it belongs to. A site that deliberately has nothing to archive
still opts out withfiles = ''.
Documentation
- The README now says that one site failing does not stop the others, which was
the undocumented half — a failed stage not stopping the ones after it was
already written down. ASkipping [cloud]line is only ever--no-cloud,
never the consequence of an earlier failure, and that is now stated where
someone reading a bad night's log will find it. - The installation section no longer promises a
SHA256SUMSon every release
without one existing. 7.0.0, 7.1.0 and 7.2.0 have been given one after the
fact — checked against the published assets rather than against a local build
— so the documented check now works for every 7.x release, not just the newest.
wback 7.3.0
[7.3.0] - 2026-08-23
Added
- A run summary: one Slack message per
cronrun, saying what the run did — sites,
backups, bytes written, how long it took, which stages ran, and any failures
named by site and stage. SetBACKUP_SUMMARY_SLACK_WEBHOOK, and
BACKUP_SUMMARY_NOTIFY=failureif only the bad nights are wanted. This is what
a log channel structurally cannot do: logging posts a record at a time, so it
can only ever report trouble, and a run where nothing fails is silent in exactly
the way an uninstalled cron entry is. The log channel stays as the backstop. - A run that finished in under a second reports
<1srather than0s, which read
as a duration nobody measured. - A run blocked by the lock reports too —
Backup did not run, naming the holder
— which used to leave nothing behind but a single log line. app:validateposts a test message to the summary webhook and fails if Slack
refuses it. A mistyped or revoked webhook is otherwise invisible until it
matters.app:configreports the summary settings and whether the log channel's Slack
webhook is set. Both webhooks are reported as set or not set, never printed.- Every log record is stamped with the machine it came from, so one Slack webhook
can serve a whole fleet instead of one per installation to tell the alerts
apart.LOG_HOSTNAMEsets the label and defaults to the system hostname; an
empty value turns the stamp off.LOG_SLACK_USERNAMEdefaults to it too. app:configandapp:validatereport the hostname label.
Changed
- The "Backup written" log entry carries the size twice:
bytesas before, and
sizerounded and with a unit, so a log can be read without converting the
large numbers by hand. - A failed site is logged with the site, domain and stage as context, where it
used to be the exception message alone — a failed process says which command it
was but nothing about whose backup it belonged to. app:configandapp:validatedraw their output with
hampel/console-report rather than
with private copies of the same renderers. The output is unchanged, byte for
byte, apart from the last two fixes below. The minimum is^2.0, whose only
break is that the renderers are handed the command's output rather than calling
back into it — which is what lets the same package serve consoles that are not
Laravel.
Fixed
app:configno longer reports an environment file it never opened. With no
.envin any of the places wback looks, it used to print the framework's guess
— which inside a built binary is aphar://path into the read-only archive,
indistinguishable from a real answer on the one line an operator reads first
when a setting is not taking effect. It now names the file it actually read, or
saysnone foundand lists where it looked.- A command name wback does not recognise is now an error that exits non-zero and
suggests the nearest match. Laravel Zero proxies an unrecognised name to the
default command, sowback app:validteprinted the command list and exited 0 —
which reads as a passing check to cron, to a deploy script, and to anything else
that gates onapp:validate. app:configprinted every path with the project directory silently removed —
the environment file as.env, the backup destination asstorage/backup—
because Laravel's two-column component runs its values through a mutator that
stripsbase_path()and cannot be turned off. The rows are rendered directly
now, and a value too long for the line wraps rather than being truncated.- A relative path in
app:configis reported along with the working directory it
resolves against, and an unset remote asnot set, rather than either passing
for a setting that is in order. - Anything resembling a password in
BACKUP_MYSQLDUMP_OPTIONS,
BACKUP_CLOUD_OPTIONSorBACKUP_SYNC_OPTIONSis redacted fromapp:config,
which is the output that gets pasted into support tickets. It covers the usual
flag spellings; credentials still belong in a defaults file. - An empty
BACKUP_SHELL— a legitimate setting, meaning "run pipelines under
the system shell" — is reported asnonebyapp:config. It used to render as
a line of dots indistinguishable from a section heading. - A check row in
app:validatewith no detail no longer ends in trailing spaces. app:configno longer reports aphar://path as relative to the working
directory. A stream wrapper URI locates a resource outright, so there is nothing
for it to be relative to — and inside a built binarybase_path()is one, which
is where the environment file lands when none of the places wback looks for it
has one. Fixed upstream inhampel/console-report1.0.1, and carried forward
unchanged in the 2.0 this now requires.
Documentation
- What happens when
cloudandsyncshare one rclone remote: the branches they
write to, and the single case where a directory of your own in a site's backup
root ends up inside the sync destination and is deleted by the next sync. - The run summary: how to read one, when it is sent, and what a run that never
started looks like. - The installation instructions no longer name one particular release, and the
checksum step now works. It downloaded the binary under a different name from
the oneSHA256SUMSlists, sosha256sum -ccould not find the file it was
meant to be checking — and it ran after the install rather than before it.
Upgrading
- Nothing is required. Every change below is either invisible or opt-in.
- To turn the run summary on, set
BACKUP_SUMMARY_SLACK_WEBHOOK. It is off
until you do, and theslacklog channel is unaffected either way — the two
are complementary, andconfig/backup.phpsays why. app:validatenow posts. It writes a message at every log level and, if a
summary webhook is configured, sends a test message to it. That is deliberate —
a revoked webhook is otherwise invisible from the sending end — but it means
running it puts messages in whatever channel this installation reports to.- A mistyped command now fails.
wback app:validteused to print the command
list and exit 0. Anything that gates on an exit code will start seeing a typo it
had been passing.
wback 7.2.0
[7.2.0] - 2026-08-14
Added
- A
portkey for sites whose database is not on the default port. croncan skip individual stages:--no-database,--no-files,--no-cloud,
--no-sync,--no-clean. For backing up locally on a machine whose cloud
credentials are not configured yet, or never will be. A stage that is meant to
run and cannot still fails the run.- The environment file can live somewhere other than beside the binary: at
/etc/wback/.env, or whereverWBACK_ENVpoints. A binary on the path can now
take its configuration from/etc/wbackand be run from anywhere. app:configreports which environment file was read.
Changed
- The default timezone is now
UTC, where it wasAustralia/Sydney— a
default inherited from the machine this was written on rather than one that
suits anybody else. SetAPP_TIMEZONEto keep the old behaviour; see
Upgrading.
Fixed
app:validatereports the error from a failed command rather than a warning
printed ahead of it, which was hiding the reason for the failure.LARAVEL_STORAGE_PATHnow works when set in the environment file. It was read
before the file was loaded, so it only ever worked as a real environment
variable.
Documentation
mariadb-dumpworks as the dump binary; MariaDB 11 renamed its clients and
keepsmysqldumpas a symlink.- Corrected what the working directory decides: the storage path is only ever a
default for the sites file, the backup destination and the log, so setting
those absolutely makes the working directory irrelevant.
Upgrading
- Set
APP_TIMEZONEbefore upgrading if you were relying on the old default.
Datestamps in backup filenames follow this setting, so a site backing up at
3am in Sydney will start naming its files with the previous day's date under
UTC. Existing backups are not touched, andcleanexpires by modification
time rather than by the name, so nothing is lost either way — but the names
will step back a day at the changeover.
wback 7.1.0
[7.1.0] - 2026-08-13
Changed
- Upgraded to Laravel Zero 13 (Laravel components 13.x), which raises the minimum
PHP version to 8.3. Nothing in the application changed: the suite passes
untouched, and a compiled binary still readsAPP_TIMEZONEfrom the.env
beside it.
wback 7.0.0
[7.0.0] - 2026-08-13
A release about trusting the backups: several ways they could fail quietly are
now loud, and the things that made them quiet are gone.
This release breaks existing installations. See Upgrading below.
Added
croncommand, running every backup in turn from a single cron entry, each
stage starting when the one before it has finished.app:validate, replacingapp:test: runs every configured binary, dumps every
schema to/dev/nullthrough the same credentials the backup uses, lists every
remote, walks the sites file, checks the destination and takes the lock. Exits
non-zero if anything failed, so it works as a post-deploy check.- Dumps are read back and checked for the marker mysqldump writes when it
finishes, catching a dump that exits 0 having written half a database
(BACKUP_MYSQLDUMP_VERIFY, per siteverify). --single-transactionon dumps, so a backup no longer read-locks every table
in the database for as long as the dump and compression take
(BACKUP_MYSQLDUMP_SINGLE_TRANSACTION, per sitesingle_transaction).- A floor under retention, keeping the most recent days of backups whatever their
age, so a run of failures can no longer expire the last ones that worked
(BACKUP_KEEPLEAST_DAYS). - A lock, so two backup runs cannot overlap and
cloudcannot upload an archive
thatfilesis still writing (BACKUP_LOCK_FILE). syncrefuses a source directory that has become empty, which is what an
unmounted filesystem looks like and would otherwise empty the remote copy
(BACKUP_SYNC_ALLOW_EMPTY).BACKUP_SYNC_BACKUP_DIR, moving everythingsyncwould replace or delete into
a dated directory on the remote instead of destroying it.- Passthrough options for the tools:
BACKUP_MYSQLDUMP_OPTIONS(per site
options),BACKUP_CLOUD_OPTIONS,BACKUP_SYNC_OPTIONS. BACKUP_SHELL, the shell used for the dump pipeline, which needspipefail.APP_TIMEZONEnow works, including in a built binary.- The size of each backup is logged, with the byte count in the log context.
- A test suite (126 tests), a README describing the whole tool, and a LICENSE
file for the MIT license the package metadata was already claiming.
Changed
--alltakes precedence over a site named on the command line, and reports the
ignored argument. Previously the site argument won and--allwas ignored.- A site that fails no longer stops the rest of an
--allrun; failures are
reported per site and the run still exits non-zero. - A failed backup command has its partial output file removed.
- Values from the site inventory are quoted before they reach the shell, so
spaces and punctuation in names, paths and patterns are safe. Configured binary
paths are deliberately still inserted as written. cloudandsyncreport with--stats-one-line --stats 1mwhen the output is
not a terminal, rather than a progress display that redraws itself into your
log files.app:sitesshows settings that are deliberately turned off, and prints
booleans astrue/falserather than1and nothing.- The package identifies itself as
hampel/wbackrather than the Laravel Zero
skeleton it grew from.
Fixed
- A
mysqldumpthat failed was masked by thegzipit was piped into, which
compressed the partial output and exited 0 — recording a truncated dump as a
successful backup. Pipelines now run under a shell withpipefail. - A dry run created the destination directories and warned that it could not
change the permissions of the file it had declined to write. - Backups failed outright with
The provided cwd … does not existon any
checkout without astoragedirectory. - The timezone was frozen at build time in a compiled binary, because
app:build
evaluatesconfig/app.phpand compiles the result in as literals. The setting
moved toconfig/backup.php, which is compiled as written.
Removed
- Laravel Zero's scheduler, and the
schedule:run,schedule:listand
schedule:finishcommands, which cannot run these commands at all: a due event
needs a trait from a package console applications do not install, a compiled
binary hands Symfony Process aphar://working directory it rejects, and
ScheduleRunCommandreports success either way. Usecron. SCHEDULE_START, with scheduling.app:test, replaced byapp:validate.- The
--forceoption oncloudandsync, left over from a hand-rolled
transfer that tracked its own last run time.
Upgrading
- Change your cron entries. Anything calling
wback schedule:runwill now
fail rather than silently do nothing. Use one entry callingwback cron --quiet, or keep an entry per command. See the README. app:testis nowapp:validate, and worth running once on each server
after upgrading — it checks everything this release added.- Expect new failures on real problems. A truncated dump, a sync source that
has gone empty, and a backup that starts while another is still running now
report failure rather than passing quietly. That is the point of the release,
but it does mean a formerly green run can go red. - Check
single_transactionfor any site with MyISAM tables holding data you
need consistent. Dumps now come from an InnoDB snapshot by default. - Remove
SCHEDULE_STARTfrom your.env; it is no longer read. - If you set
APP_TIMEZONEand it was being ignored, it now takes effect —
which can move the date in backup filenames.