mirror of
https://github.com/kellymichels/zscripts-token-savers
synced 2026-10-06 07:08:17 +00:00
Some checks failed
tests / test (push) Has been cancelled
Build stamp catch-up for 4 merged PR(s) since v1.0.0.0.27:b26be3cchore: write the site name as evomedia.net, lowercase (#92)22a7387feat(site): link preview for zscripts.evomedia.net, with a card in the page's own colours (#91)86938d0chore: publish the zec2 and zec2online comment updates to the mirror (#87)90f4301fix: pin the .txt twins to LF so regenerating them stops reporting a change (#89)
381 lines
20 KiB
Markdown
381 lines
20 KiB
Markdown
<!--
|
|
evomedia.net Token Savers — https://github.com/evomedia-net/evo.zscripts
|
|
Created by Kelly Michels · dev@evomedia.net
|
|
Licensed under the MIT License. See LICENSE.
|
|
-->
|
|
|
|
# Changelog
|
|
|
|
Notable changes to the evomedia.net Token Savers.
|
|
|
|
## Unreleased
|
|
|
|
## v1.0.0.0.28 - 2026-09-22
|
|
|
|
### Changed
|
|
|
|
- **`zec2` and `zec2online` comments now say what they mean without
|
|
naming private detail.** The container-side version read is described
|
|
by what it is - an endpoint that is not public on every project - rather
|
|
than by a product's own wording, and `zec2` records why it needed its
|
|
own ssh: the read referenced three variables the script never defined,
|
|
and because it sits inside a try/catch the failure was silent and looked
|
|
exactly like a service that could not be reached.
|
|
|
|
## v1.0.0.0.26 - 2026-09-14
|
|
|
|
### Fixed
|
|
|
|
- **`zdeploy` on a docker stack built from source shipped nothing after the
|
|
first deploy.** The docker kind ran `docker compose pull` and then
|
|
`docker compose up -d`, which is right for a stack of published images and
|
|
wrong for one built from a `Dockerfile` in the tree: there is nothing to
|
|
pull, and `up -d` builds only when the image is *missing*. So the first
|
|
deploy worked and every one after it uploaded the new code, started the old
|
|
image, and reported success — worse than an error, because the deploy is
|
|
green and the container is healthy. A project now opts into building with
|
|
`"deploy": { "build": true }`, which runs `docker compose build --pull` so
|
|
the base image is refreshed at the same time. Stacks that pull are
|
|
unaffected.
|
|
|
|
## v1.0.0.0.25 - 2026-09-12
|
|
|
|
### Added
|
|
|
|
- **`zmerge`** — merge every pull request across the org that is genuinely
|
|
ready (`MERGEABLE` / `CLEAN`, not a draft), re-checking each one immediately
|
|
before and after every merge, because merging into a default branch can
|
|
conflict a sibling PR in the same repository. Dry run by default;
|
|
`-Execute` (or `-e`) merges.
|
|
- **`zpull`** — `zmerge`, then `git pull --ff-only` in every checkout the
|
|
merges affected. Skips a checkout that is dirty or is not on its default
|
|
branch rather than guessing.
|
|
|
|
### Changed
|
|
|
|
- **`-e` is an alias for `-Execute`** on both of the above, the way `-s`
|
|
already works for `-Scan`.
|
|
- **`zmerge` discovers repositories instead of listing them.** It asked a
|
|
hand-kept list, which had fallen well behind the org - so a scan covered
|
|
about half of it and reported "Nothing open to merge" while a ready pull
|
|
request sat in a repository the list had never heard of. It now asks GitHub,
|
|
and throws rather than returning an empty list if that fails: a tool that
|
|
quietly scans nothing prints the same reassuring line as one that scanned
|
|
everything, and the two must not be confusable.
|
|
|
|
## v1.0.0.0.24 - 2026-09-08
|
|
|
|
### Added
|
|
- **`zdeploy` can lay the release tag it already knows the number for.**
|
|
A versioning scheme that asks every release to carry an annotated tag needs
|
|
something to enforce it, and for a project whose build number lives outside
|
|
git - in a database, say - nothing did: one project reached thirty-eight
|
|
builds with four tags, and the missing ones were unrecoverable because the
|
|
number had never existed anywhere else. With `deploy.tagOnDeploy`, the
|
|
deployed commit is tagged with its build number and pushed, but only after
|
|
the live build has been *verified* - a tag is a claim about what is running.
|
|
Opt-in, because a project that already tags releases through a pull request
|
|
must not also collect a tag per deploy. It can never fail a deploy: an
|
|
existing tag is left alone, a failed push keeps the tag local and prints the
|
|
command to finish it, and a missing repo just says so.
|
|
|
|
### Fixed
|
|
- **The mirror stopped publishing current product names.** Its own denylist
|
|
never saw the current spellings (a dot or hyphen breaks the word, an
|
|
underscore hides the boundary), so twelve references went out while the
|
|
suite ran green. The patterns learn the spellings, planted cases prove it,
|
|
and the references read generically now.
|
|
- **`zstart` no longer aborts on a pull that succeeded.** git reports
|
|
ordinary fetch progress (`From https://...`) on stderr, and under Windows
|
|
PowerShell 5.1 the script's `2>&1` turned that into a terminating error -
|
|
so a pull that had *worked* stopped the dev server from starting, before
|
|
the script's own "Auto-pull skipped" branch could run. The pull now lives
|
|
in `Invoke-StartGitPull`, which never throws, never switches branch, and
|
|
never touches a dirty tree: it fast-forwards when it can, reports when it
|
|
can't, and `zstart` carries on either way - the opposite failure mode
|
|
from `Invoke-DeployGitPull`, on purpose. Fourteen tests drive real git
|
|
under `Stop` on 5.1, the host the defect lives on (#130).
|
|
|
|
## v1.0.0.0.23 - 2026-08-31
|
|
|
|
### Changed
|
|
- **Every release since 1.0.0 has its own section again** - 21 entries had
|
|
piled up under `Unreleased` while 22 builds shipped, so this file said
|
|
nothing had been released since 1.0.0 and a reader at any tag found no
|
|
section for the version they were holding. Which release carried which
|
|
entry was derived from git, not guessed: for every line, the commit that
|
|
introduced it, then the earliest tag containing that commit. No entry text
|
|
changed - only headings were added and whole entries moved under the
|
|
release that carried them.
|
|
- **`scripts/readme_txt.py` is now `scripts/plaintext_twins.py` and covers
|
|
every markdown file that owes a twin**, `CHANGELOG.txt` included. It was
|
|
kept by hand, so it drifted the moment this file was reorganised. The
|
|
renderer also drops `<!-- -->` markers, which are invisible in markdown
|
|
and read as stray punctuation in a text file.
|
|
|
|
### Fixed
|
|
- **The `--check` that keeps the twins honest is actually run now** -
|
|
`readme_txt.py` shipped one and its docstring claimed "the test suite runs
|
|
--check", but nothing invoked it, so a twin could disagree with its
|
|
markdown indefinitely. `tests/PlainTextTwins.Tests.ps1` runs it, and
|
|
reports *inconclusive* rather than passing when python is unavailable.
|
|
|
|
## v1.0.0.0.22 - 2026-08-31
|
|
|
|
### Changed
|
|
- **The sanitization denylist moved to `tests/sanitization-patterns.psd1`**,
|
|
so the test suite here and the publisher in the private toolkit read one
|
|
list instead of keeping two. They had two, and they disagreed: the
|
|
publisher's scan looked only for secrets, while these rules are about
|
|
identity — internal project names, product domains, private-only script
|
|
names, operator paths. It therefore reported "clean" on files this suite
|
|
rejects. No rule changed; only where they live.
|
|
|
|
## v1.0.0.0.21 - 2026-08-31
|
|
|
|
### Added
|
|
- **`tests/VerifyPlan.Tests.ps1`** — the verification channel-selection rules
|
|
are pure functions in `ZHelpers.ps1` (`Get-VerifyAttempts`,
|
|
`Get-VerifyTimeout`) and Pester pins them, including "a project with no
|
|
domain must never produce an edge attempt" and the PowerShell 5.1
|
|
one-element-unroll trap.
|
|
|
|
- **`scripts/readme_txt.py` and `README.txt`** — a generated plain-text twin
|
|
of the README for terminals and pagers. `README.txt` is generated, never
|
|
edited by hand.
|
|
|
|
### Changed
|
|
- **`zdeploy` verification picks its channel on every retry, and never asks
|
|
the bare IP** — the check used to choose its channel once, before the wait
|
|
loop, by probing; the probes raced the app restart the check exists to wait
|
|
through, so the whole window went to the edge fallback. For a project with
|
|
no `domain` that fallback had no `Host` header, and the proxy can then only
|
|
answer from its **default vhost — a different product**: that is how one
|
|
deploy's check compared another app's build number against its own. Now
|
|
channels are re-resolved each retry in trust order (docker-network
|
|
`viaProxy` → `localhost:<port>` → edge with the project's `Host`), the edge
|
|
is skipped entirely when there is no host to route by, and a project with
|
|
no trustworthy channel is reported as unverifiable instead of guessed at.
|
|
The final warning also says which failure happened: a version that never
|
|
matched (stale/failed build) reads differently from channels that never
|
|
answered (probably still booting). `verify.timeoutSeconds` joins the
|
|
config so a project that is slow to boot — e.g. one that runs database
|
|
migrations in its entrypoint — can widen its own window instead of
|
|
warning on every routine success.
|
|
|
|
- **An interrupted deploy can no longer destroy server-side `.env` files** —
|
|
the preserve/restore of operator files is transactional: the restore comes
|
|
from a tarball taken before the tree is replaced, so a deploy that dies
|
|
mid-flight leaves the previous files in place instead of an empty
|
|
directory.
|
|
|
|
- **A successful deploy no longer reports failure** — `docker compose
|
|
restart` writes routine progress to stderr, which PowerShell 5.1 turns
|
|
into a terminating error under `$ErrorActionPreference = 'Stop'`; four ssh
|
|
calls bypassed the wrapper that flattens this. All remote steps now run
|
|
through it and are judged by exit code alone.
|
|
|
|
## v1.0.0.0.20 - 2026-08-30
|
|
|
|
### Changed
|
|
- **`zversion bump` is once per *release*, not once per PR** — the usage text
|
|
and the `bump` help line both said "one per PR, one per defect fix". The
|
|
build number names something that shipped, so a release carrying five PRs
|
|
moves it by one; PRs that never shipped on their own were never separate
|
|
builds. Help text only here, but it is the wording people follow: it stamped
|
|
a single evo.www release as two builds. The historical entry below, which
|
|
records what the rule was when `zversion` shipped, is deliberately left as
|
|
written.
|
|
|
|
## v1.0.0.0.19 - 2026-08-30
|
|
|
|
### Added
|
|
- **Read a live build from inside the docker network, not through the public
|
|
proxy** — `zdeploy`, `zec2` and `zec2online` now prefer
|
|
`docker exec <viaProxy> curl http://<upstream>/api/build-version` when a
|
|
project sets `verify.viaProxy` and `verify.upstream`.
|
|
|
|
Two problems it closes. A build stamp is something many sites deliberately
|
|
do not serve publicly, and a checker that reads it over the public URL stops
|
|
working the moment that endpoint is blocked — reporting "unknown", which is
|
|
indistinguishable from "could not reach it". And the proxy answers from
|
|
whichever vhost matches the Host header, so a container with no public route
|
|
was getting *another site's* version back and failing deploys that had
|
|
worked.
|
|
|
|
Reading it from a container on the shared network also exercises the real
|
|
HTTP path, so it proves the app is serving rather than that its database
|
|
knows a version. Purely additive: projects without those two keys behave
|
|
exactly as before.
|
|
|
|
## v1.0.0.0.14 - 2026-08-20
|
|
|
|
### Fixed
|
|
- **`scp` no longer receives an ssh-only flag** — the stdin-hang fix added
|
|
`-n` to `Get-Ec2SshOpts`, and the deploy path splats that same array into
|
|
`scp` as well as `ssh`. OpenSSH's `scp` has no `-n`: it exits 1 with
|
|
`unknown option -- n` and prints its usage block, so every upload failed.
|
|
`Get-Ec2ScpOpts` now supplies the shared connection options with `-n`
|
|
filtered out, derived from `Get-Ec2SshOpts` rather than duplicated so the
|
|
timeouts cannot drift apart between the two transports. All four `scp`
|
|
call sites use it, including the recursive directory upload.
|
|
The upload failure message also asserted "Likely server disk space"
|
|
without checking; it now points at `scp`'s own output, where the real
|
|
diagnosis already was.
|
|
|
|
## v1.0.0.0.8 - 2026-08-12
|
|
|
|
### Fixed
|
|
- **Deploys can no longer hang forever on an ssh prompt** — every
|
|
deploy-path `ssh`/`scp` now carries `BatchMode=yes` plus connect and
|
|
keepalive timeouts (`Get-Ec2SshOpts` in `ZHelpers.ps1`). Without
|
|
`BatchMode`, ssh prompts for a passphrase or password and waits
|
|
indefinitely; because the deploy pipes stderr through the pipeline, the
|
|
prompt never reaches the screen and the run just stops under whatever
|
|
step label printed last, with no explanation. Now it fails immediately —
|
|
there is no prompt on this path worth answering. `ServerAlive*` bounds a
|
|
session that dies mid-command (dropped VPN, sleeping laptop, rebooting
|
|
host) to about a minute instead of hanging.
|
|
|
|
- **Vendored archives survive the archive filter** — files under a
|
|
`vendor/` directory are exempt from the "no archives in the zip" rule.
|
|
A project that vendors a dependency as `vendor/*.tgz` needs it in the
|
|
deploy zip; dropping it makes a Dockerfile's `COPY vendor ./vendor`
|
|
fail at image build, a confusing way to learn the filter ate a build
|
|
input.
|
|
|
|
- **`unzip` install is idempotent** — the remote step ran
|
|
`apt-get update && apt-get install -y unzip` on every deploy; it now
|
|
checks `command -v unzip` first and skips the apt round-trip when the
|
|
binary is already there.
|
|
|
|
- **`zdeploy` edge kind now ships asset subdirectories** (#42) — the edge
|
|
deploy uploaded top-level files only, so a project self-hosting assets
|
|
in folders (`fonts/`, `vendor/`) lost them on every deploy: docker
|
|
created empty root-owned mount points and nginx served 404s from them,
|
|
which shows up as fonts silently falling back and vendored JS never
|
|
loading. Every subdirectory except `nginx-logs/` and `.git/` now ships
|
|
recursively, and the `ensure edge dir` chown is recursive so scp into
|
|
docker-created root-owned dirs cannot fail.
|
|
|
|
## v1.0.0.0.0 - 2026-07-28
|
|
|
|
### Added
|
|
- **Versioned releases: `zversion`, `zrelease`, `releases/`** — the toolkit now
|
|
carries one version in a 5-segment scheme,
|
|
`v{major}.{rc}.{beta}.{alpha}.{build}`. `zversion bump` (one per PR / defect
|
|
fix) and `zversion bump-stage release|rc|beta|alpha` (zeroes every lower
|
|
segment) rewrite `build-version.json`, stamp `# Version:` into every script
|
|
header — so a lone copied script still says which release it came from — and
|
|
regenerate `CHECKSUMS.txt` in the same step. `zrelease` packages the current
|
|
version as `releases/zscripts-<version>.zip` with a `.sha256` beside it: one
|
|
hash verifies the download, the bundled `CHECKSUMS.txt` verifies the
|
|
extracted contents, so nobody needs to clone the repo to get a verifiable
|
|
copy. Released zips are immutable — `zrelease` refuses to overwrite one.
|
|
|
|
- **`zchecksums` + `CHECKSUMS.txt`** — a SHA-256 manifest covering every `.ps1`
|
|
and `.cmd`, so a download can be verified before anything is run. `zchecksums`
|
|
checks them; `zchecksums -Update` regenerates after an intentional edit. The
|
|
manifest is `sha256sum` format, so `sha256sum -c CHECKSUMS.txt` works on
|
|
Linux/macOS/WSL too, and the hashes match on every platform because
|
|
`.gitattributes` pins these files to CRLF everywhere. Flags changed files,
|
|
missing files, **and scripts present on disk but absent from the manifest**.
|
|
It's an integrity check, not a signature — the manifest sits in the same repo
|
|
as the code, so it catches corruption and accidental drift, not a compromised
|
|
repo. A Pester test fails if the manifest ever goes stale.
|
|
|
|
- **Test suite (Pester)** — the toolkit now has automated coverage of its own
|
|
pure logic: `Get-ArchiveExcludes` (including the deploy-vs-backup rule that
|
|
keeps `.env`/`uploads` out of deploys but *in* backups), config and project
|
|
lookups, `remote.composeDir` fallback, EC2 target composition, and build-label
|
|
formatting. Run with `Invoke-Pester .\tests` (Pester 5+). Verified by mutation
|
|
testing — reintroducing each historical bug turns the suite red.
|
|
|
|
- **`ZCONFIG` environment variable** — overrides the path to `zconfig.json`, so
|
|
a run can target an alternate config. Also gives the test suite a seam for
|
|
injecting a fixture.
|
|
|
|
- **`zec2_rotatekeys` — safely rotate/reset server-side secrets** — a new
|
|
tool for when a secret leaks or a deploy overwrites a production `.env`
|
|
with dev values. `-Rotate KEY` regenerates a key **on the server**
|
|
(`openssl rand -hex 32`) so the new value never leaves the box; `-Set KEY`
|
|
takes an operator-known value (e.g. `DATABASE_URL`, `ADMIN_EMAIL`) from a
|
|
masked prompt and streams it over SSH stdin — never a command argument,
|
|
never echoed. Backs the server `.env` up to a timestamped `.bak` first,
|
|
updates the key atomically (matches or appends), auto-detects
|
|
`backend/.env` from `deploy.preserve`, and with `-Restart` **recreates**
|
|
the container (`up -d --force-recreate`, so the new values actually load —
|
|
a plain restart keeps the old environment). `-WhatIf` previews the plan
|
|
without touching anything.
|
|
|
|
- **`zkill all`** — `zkill` now accepts `all`, stopping the dev server of
|
|
every project that has a `ports.dev` (edge/docker stacks with no local dev
|
|
server are skipped). Brings it in line with `zdeploy all` / `zbackup all`;
|
|
the one-shot "stop everything I've got running locally".
|
|
|
|
- **`zdeploy` server-side health verification (`verify` block)** — projects
|
|
not published through the edge proxy can declare
|
|
`"verify": { "port": ..., "path": "/health", "expect": "..." }` and the
|
|
deploy is checked from the server itself (`curl localhost:<port><path>`
|
|
over SSH) instead of hitting the public IP. Fixes a false PASS where the
|
|
proxy's default vhost answered for apps that never started; projects
|
|
with neither `domain` nor `verify` are now reported as NOT verified.
|
|
|
|
- **`zdeploy` optional `deploy.gitPull`** — `git pull --ff-only` in the
|
|
project root before zipping. `zdeploy` zips the working tree and doesn't
|
|
otherwise pull, so a checkout left behind `origin` after a merged PR would
|
|
deploy stale code while still bumping the build number — success that
|
|
changes nothing. A failed pull aborts the deploy instead.
|
|
|
|
- **Per-project `start` config block** — `zstart` honors optional pre-start
|
|
steps from `zconfig.json`: `"gitPull": true` runs `git pull --ff-only` in
|
|
the project root before starting (never boot a stale checkout), and
|
|
`"env": { ... }` sets environment variables for the dev-server process.
|
|
Example added to `zconfig.example.json`.
|
|
|
|
- **Switch-style argument tolerance** — a leading dash on a project key is
|
|
ignored everywhere (`zdeploy -myapp` == `zdeploy myapp`), for hands that
|
|
grew up on per-project switches.
|
|
|
|
### Changed
|
|
- **`zbackup` / `zbackup_and_sync` require an explicit target** — running
|
|
them bare now shows usage instead of quietly backing up every project;
|
|
`all` does what bare invocation used to (matching `zdeploy`). The
|
|
scheduled task created by `setup_backup_schedule.ps1` passes `all` —
|
|
re-run it if your task was registered before this change.
|
|
|
|
- **`zbackup` parses more `DATABASE_URL` styles** — double/single-quoted
|
|
values (Prisma convention), `postgres://` and `postgresql+driver://`
|
|
schemes, and URLs without an explicit port (defaults to 5432) all work;
|
|
previously these skipped the Postgres dump with "Could not parse
|
|
DATABASE_URL".
|
|
|
|
- **`zkill` / port cleanup kills the whole process tree** — listeners on a
|
|
project's port are now terminated children-first. Auto-reloading servers
|
|
(uvicorn/watchfiles, nodemon) spawn workers that inherit the listening
|
|
socket; killing only the parent left orphans serving stale code.
|
|
|
|
- **`zbackup` finds `DATABASE_URL` in `backend\.env` too** — projects with a
|
|
frontend/backend split get their Postgres dump bundled without needing a
|
|
root-level `.env`.
|
|
|
|
### Fixed
|
|
- **`zdeploy` no longer deletes operator-managed files on deploy** (#2) —
|
|
the project-directory replacement preserved only `./.env`, silently
|
|
destroying every other server-side file (`.env.db`, staged signing
|
|
keys, certs) on every deploy. All `.env*` files at the project root are
|
|
now preserved by default, plus anything listed in the new
|
|
`deploy.preserve` array (files or directories); the vite kind, which
|
|
previously preserved nothing, gets the same protection. Found the hard
|
|
way: a first production deploy of an auth service wiped its staged DB
|
|
credentials and RSA signing keys.
|
|
|
|
## 1.0.0
|
|
|
|
Initial public release: `zstart` / `zkill` / `zrestart` (local dev servers),
|
|
`zdeploy` (zip → upload → compose build → live build-version verification,
|
|
with handlers for python / vite / nextjs / edge / docker project kinds),
|
|
`zec2` / `zec2online` / `zrepair` (health checks and recovery), `zbackup` /
|
|
`zbackup_ec2` / `zsync` (local, server-side, and offsite backups), all driven
|
|
by a single gitignored `zconfig.json`.
|