export: a dry run that predicts failures and exits as the real run would
ci / test (pull_request) Skipped
github/ci (branch) GitHub Actions
ci / github (pull_request) Successful in 2m30s
ci / announce (pull_request) Skipped

export --dry-run counted what it would create and printed a table, but it
missed the failures it could see coming and always exited 0.

It now checks, before anything is written:
- a message larger than the target's maxSizeUpload;
- an object too large for one request under maxSizeRequest, as a contact
  with its photo inlined can be;
- a Sieve script the target would reject, with SieveScript/validate, after
  the vnd.stalwart names are renamed, so what is checked is what would be
  uploaded. Sieve scripts are uploaded as blobs for that check, and nothing
  else is; a target without the method gets one warning.

The counts are kept instead of being dropped, so a dry run in which
anything would fail exits 5, like the real run. The report is now a plan in
plain words -- per type, what would be created, updated, left unchanged,
deleted and would fail -- followed by each predicted failure and why.
This commit is contained in:
2026-09-30 12:46:38 -07:00
parent 1d63dfe25e
commit e47c074d43
7 changed files with 668 additions and 18 deletions
+19
View File
@@ -246,6 +246,25 @@ failed.
`--prune` also deletes what is on the target and not in the archive. It asks
first; `--yes` answers for it, for scripts. Export speaks JMAP only.
With `--dry-run`, export reads the target and writes nothing to the account.
It prints the plan in plain words: for each type, how much would be
created, updated, left unchanged or deleted, and what would fail. It
catches in advance the failures a real run would hit:
- a message larger than the target's `maxSizeUpload`;
- a contact, event or other object too large for one request under its
`maxSizeRequest`, as happens when a photo is carried inline;
- a Sieve script the target would reject. Each script that would be written
is checked with `SieveScript/validate`, after any `vnd.stalwart.*` names
are renamed, so what is checked is what would be uploaded. The check needs
the script as a blob, so the dry run uploads Sieve scripts, and only them;
a blob that nothing uses is discarded by the server. A target without
`SieveScript/validate` gets one warning, and its scripts are not checked.
The plan lists each predicted failure and its reason. When anything would
fail, the dry run exits 5, as the real run would, so a script can stop
before it starts.
## Inspect
```