Files
fuj-management/docs/plans/2026-05-07-1033-fuj-sync-dry-run.md
Jan Novak 36a28a40d2
All checks were successful
Deploy to K8s / deploy (push) Successful in 18s
feat(go): add --dry-run to fuj sync
Mirror fuj infer's read-only mode: SyncOpts.DryRun skips WriteHeader,
AppendValues, and SortByDateColumn, printing one "Dry run: would …"
line per planned operation instead. ID-dedup still runs so the output
reflects exactly what the next real sync would write.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 10:33:55 +02:00

2.0 KiB

Plan: add --dry-run to fuj sync

Context

fuj infer already supports --dry-run (it builds the planned BatchUpdateValues operations, prints them, and skips the actual write — see go/internal/services/banksync/infer.go:136-156 and the Dry run: would update N row(s). line in go/cmd/fuj/main.go:209-213).

fuj sync had no equivalent. It always committed three potential writes to the payments sheet: WriteHeader (if the header row is missing/wrong), AppendValues (for each new Fio transaction), and SortByDateColumn (if --sort, default true). For inspecting what a sync would do — useful when debugging dedupe, sanity-checking a date window, or wiring up the command for the first time on a new account — the only options were pointing at a throwaway spreadsheet or reading the diff after the fact.

This change mirrors infer's read-only mode for sync: same flag name, same output style, same "build the data structures, print instead of writing" shape.

Files modified

  1. go/internal/services/banksync/sync.goDryRun bool field added to SyncOpts; three write points gated on opts.DryRun
  2. go/cmd/fuj/main.go--dry-run flag added to syncCmd; final println split on *dryRun
  3. go/internal/services/banksync/sync_test.goTestSyncToSheets_DryRun added
  4. CHANGELOG.md — entry added

Behaviour

When --dry-run is set:

  • If the sheet header is missing/wrong → prints Dry run: would write header row; skips WriteHeader
  • For each non-deduped Fio transaction → prints Dry run: would append date=… amount=… sender=… vs=… message=…; skips AppendValues
  • If --sort is true → prints Dry run: would sort by date; skips SortByDateColumn
  • Returns len(newRows) so the caller can print Dry run: would sync N new transaction(s).

The existing ID-dedup logic runs in full even during dry-run (reads the sheet, builds existingIDs), so the output reflects exactly what the next real sync would do.