Compare commits
1
Commits
next
...
b72b6ded58
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b72b6ded58 |
@@ -22,6 +22,14 @@ the tag exists and is exercised; what is left is merging `next` to
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- 2026-10-06: Made `snapshot remove --json` write only its document to
|
||||||
|
stdout when the destination store cannot be reached
|
||||||
|
([issue #251](https://git.eeqj.de/sneak/vaultik/issues/251)). Its
|
||||||
|
warning that the snapshot's metadata was left on the destination store
|
||||||
|
went to stdout ahead of the document, breaking `| jq` on a command that
|
||||||
|
exited 0. Under `--json` the warning now reaches stderr only, through
|
||||||
|
the logger.
|
||||||
|
|
||||||
- 2026-10-06: Made command output follow the README's stdout and stderr
|
- 2026-10-06: Made command output follow the README's stdout and stderr
|
||||||
rules ([issue #224](https://git.eeqj.de/sneak/vaultik/issues/224)). The
|
rules ([issue #224](https://git.eeqj.de/sneak/vaultik/issues/224)). The
|
||||||
startup banner went to stdout, so a `completion` script or a
|
startup banner went to stdout, so a `completion` script or a
|
||||||
|
|||||||
@@ -87,12 +87,29 @@ func TestEntryJSONFailureIsReportedOnStderr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeUnusableDestinationConfig builds a config whose destination
|
// TestEntrySnapshotRemoveJSONWarningIsOnStderr runs `snapshot remove
|
||||||
// directory does not exist, which fails `remote info`, and whose local
|
// --json` against a destination directory that does not exist. The
|
||||||
// index is bound to another destination, which fails `prune` and
|
// command still exits 0 after removing the snapshot from the local
|
||||||
// `snapshot remove` (a missing destination alone only makes `snapshot
|
// index. Its stdout must hold the document alone, with the warning
|
||||||
// remove` warn). Returns the config path.
|
// about the destination store on stderr.
|
||||||
func writeUnusableDestinationConfig(t *testing.T) string {
|
//
|
||||||
|
//nolint:paralleltest // replaces os.Args, os.Stdout, os.Stderr and the xdg globals
|
||||||
|
func TestEntrySnapshotRemoveJSONWarningIsOnStderr(t *testing.T) {
|
||||||
|
configPath, _ := writeMissingDestinationConfig(t)
|
||||||
|
|
||||||
|
code, stdout, stderr := runEntry(t, flagConfig, configPath,
|
||||||
|
cmdSnapshot, cmdRemove, someSnapshotID, flagJSON)
|
||||||
|
|
||||||
|
require.Equal(t, 0, code)
|
||||||
|
requireExactlyOneJSONDocument(t, stdout)
|
||||||
|
assert.Contains(t, stderr,
|
||||||
|
"Could not remove snapshot metadata from remote storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeMissingDestinationConfig builds a config whose destination
|
||||||
|
// directory does not exist. Returns the config path and the path of
|
||||||
|
// its local index, which is not created here.
|
||||||
|
func writeMissingDestinationConfig(t *testing.T) (string, string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
@@ -114,6 +131,19 @@ func writeUnusableDestinationConfig(t *testing.T) string {
|
|||||||
xdg.Reload()
|
xdg.Reload()
|
||||||
t.Cleanup(xdg.Reload)
|
t.Cleanup(xdg.Reload)
|
||||||
|
|
||||||
|
return configPath, indexPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeUnusableDestinationConfig builds a config whose destination
|
||||||
|
// directory does not exist, which fails `remote info`, and whose local
|
||||||
|
// index is bound to another destination, which fails `prune` and
|
||||||
|
// `snapshot remove` (a missing destination alone only makes `snapshot
|
||||||
|
// remove` warn). Returns the config path.
|
||||||
|
func writeUnusableDestinationConfig(t *testing.T) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
configPath, indexPath := writeMissingDestinationConfig(t)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
db, err := database.New(ctx, indexPath)
|
db, err := database.New(ctx, indexPath)
|
||||||
@@ -122,7 +152,7 @@ func writeUnusableDestinationConfig(t *testing.T) string {
|
|||||||
defer func() { require.NoError(t, db.Close()) }()
|
defer func() { require.NoError(t, db.Close()) }()
|
||||||
|
|
||||||
require.NoError(t, database.NewRepositories(db).LocalMeta.Set(ctx,
|
require.NoError(t, database.NewRepositories(db).LocalMeta.Set(ctx,
|
||||||
database.LocalMetaKeyStorageURL, "file://"+filepath.Join(dir, "other")))
|
database.LocalMetaKeyStorageURL, "file://"+t.TempDir()))
|
||||||
|
|
||||||
return configPath
|
return configPath
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1167,7 +1167,7 @@ func (v *Vaultik) RemoveSnapshot(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !opts.LocalOnly {
|
if !opts.LocalOnly {
|
||||||
result.RemoteRemoved = v.removeSnapshotRemote(snapshotID)
|
result.RemoteRemoved = v.removeSnapshotRemote(snapshotID, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.SnapshotManager != nil {
|
if v.SnapshotManager != nil {
|
||||||
@@ -1252,7 +1252,7 @@ func (v *Vaultik) confirmRemoveSnapshot(snapshotID string, opts *RemoveOptions)
|
|||||||
// removal has already happened, so the user is told the remote half
|
// removal has already happened, so the user is told the remote half
|
||||||
// didn't finish and can retry with `vaultik prune` once the destination
|
// didn't finish and can retry with `vaultik prune` once the destination
|
||||||
// store is reachable. Returns true when the remote removal succeeded.
|
// store is reachable. Returns true when the remote removal succeeded.
|
||||||
func (v *Vaultik) removeSnapshotRemote(snapshotID string) bool {
|
func (v *Vaultik) removeSnapshotRemote(snapshotID string, opts *RemoveOptions) bool {
|
||||||
log.Info("Removing snapshot metadata from remote storage",
|
log.Info("Removing snapshot metadata from remote storage",
|
||||||
"snapshot_id", snapshotID)
|
"snapshot_id", snapshotID)
|
||||||
|
|
||||||
@@ -1263,7 +1263,9 @@ func (v *Vaultik) removeSnapshotRemote(snapshotID string) bool {
|
|||||||
log.Warn("Could not remove snapshot metadata from remote storage",
|
log.Warn("Could not remove snapshot metadata from remote storage",
|
||||||
"error", err)
|
"error", err)
|
||||||
|
|
||||||
if v.UI != nil {
|
// The UI writes to stdout, which under --json holds only the
|
||||||
|
// document; the log record above is the warning on stderr.
|
||||||
|
if v.UI != nil && !opts.JSON {
|
||||||
v.UI.Warningf("Could not remove snapshot metadata from remote: "+
|
v.UI.Warningf("Could not remove snapshot metadata from remote: "+
|
||||||
"%v. Run '%s' once the remote is reachable to finish cleanup.",
|
"%v. Run '%s' once the remote is reachable to finish cleanup.",
|
||||||
err, pruneCommandHint)
|
err, pruneCommandHint)
|
||||||
|
|||||||
Reference in New Issue
Block a user