mirror of
https://github.com/kellymichels/zscripts-token-savers
synced 2026-10-07 07:18:18 +00:00
Two commands that were private-only until now. They turned out to be useful
beyond the fleet they were written for, so they are manifested for publication
and removed from the sanitization denylist's private-only list.
zmerge merge every pull request across the org that is genuinely ready -
MERGEABLE/CLEAN and 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 at it.
WHY THEY COULD BE PUBLISHED NOW. zmerge carried a hardcoded list of sixteen
repository names, which was both the reason it could not be published and a
bug: the org has thirty active repositories, so it scanned about half and
reported "Nothing open to merge" while a ready pull request sat in one it had
never heard of. It asks GitHub now, and the names went with the list.
Get-FleetRepos throws rather than returning an empty list when gh fails,
because a tool that quietly scans nothing prints the same reassuring line as
one that scanned everything and found nothing.
-e is an alias for -Execute on both, the way -s already works for -Scan.
Also: __pycache__/ is gitignored. scripts/plaintext_twins.py creates it on
every run and it was showing up as untracked work.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
377 lines
18 KiB
Plaintext
377 lines
18 KiB
Plaintext
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
|
|
----------
|
|
|
|
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.
|