Skip to content

Commit 658341d

Browse files
committed
Adjust snapshot name when destination not provided: append 3 char hex
1 parent 2bf9e13 commit 658341d

3 files changed

Lines changed: 22 additions & 13 deletions

File tree

cmd/snapshot.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func newSnapshotSaveCmd(cfg *env.Env) *cobra.Command {
3333
3434
Pass [destination] as an absolute or relative path for the exported file:
3535
36-
lstk snapshot save # saves to ./snapshot-<YYYY-MM-DDTHH-mm-ss>.zip
36+
lstk snapshot save # saves to ./snapshot-<YYYY-MM-DDTHH-mm-ss>-<hex>.zip
3737
lstk snapshot save ./my-snapshot.zip # saves to ./my-snapshot.zip
3838
lstk snapshot save /tmp/my-state # saves to /tmp/my-state.zip
3939

internal/snapshot/destination.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package snapshot
22

33
import (
4+
"crypto/rand"
45
"errors"
56
"fmt"
67
"os"
@@ -18,11 +19,13 @@ var (
1819

1920
// ParseDestination resolves the user-supplied path to an absolute local path.
2021
// When dest is empty, a default name based on now (UTC) is used, e.g.
21-
// "snapshot-2026-05-11T21-04-32.zip", saved in the current working directory.
22+
// "snapshot-2026-05-11T21-04-32-a3f.zip", saved in the current working directory.
2223
// The returned path always has a .zip extension.
2324
func ParseDestination(dest string, now time.Time) (string, error) {
2425
if dest == "" {
25-
dest = "./" + now.UTC().Format("snapshot-2006-01-02T15-04-05")
26+
b := make([]byte, 2)
27+
_, _ = rand.Read(b)
28+
dest = "./" + now.UTC().Format("snapshot-2006-01-02T15-04-05") + "-" + fmt.Sprintf("%x", b)[:3]
2629
} else {
2730
lower := strings.ToLower(dest)
2831
switch {

internal/snapshot/destination_test.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package snapshot_test
33
import (
44
"os"
55
"path/filepath"
6+
"regexp"
67
"runtime"
78
"strings"
89
"testing"
@@ -30,20 +31,21 @@ func TestParseDestination(t *testing.T) {
3031
require.NoError(t, os.Mkdir(subDir, 0o755))
3132

3233
type testCase struct {
33-
name string // optional; uses input when empty
34-
input string
35-
wantPath string
36-
wantErr string
37-
wantRemoteErr bool
38-
wantSchemeErr bool
34+
name string // optional; uses input when empty
35+
input string
36+
wantPath string
37+
wantPathRegexp string // used instead of wantPath when the result contains a random component
38+
wantErr string
39+
wantRemoteErr bool
40+
wantSchemeErr bool
3941
}
4042

4143
tests := []testCase{
4244
// --- default (empty input) ---
4345
{
44-
name: "default",
45-
input: "",
46-
wantPath: filepath.Join(wd, "snapshot-2026-05-11T21-04-32.zip"),
46+
name: "default",
47+
input: "",
48+
wantPathRegexp: regexp.QuoteMeta(filepath.Join(wd, "snapshot-2026-05-11T21-04-32-")) + `[0-9a-f]{3}\.zip`,
4749
},
4850

4951
// --- local paths ---
@@ -178,7 +180,11 @@ func TestParseDestination(t *testing.T) {
178180
return
179181
}
180182
require.NoError(t, err)
181-
assert.Equal(t, tc.wantPath, got)
183+
if tc.wantPathRegexp != "" {
184+
assert.Regexp(t, tc.wantPathRegexp, got)
185+
} else {
186+
assert.Equal(t, tc.wantPath, got)
187+
}
182188
})
183189
}
184190
}

0 commit comments

Comments
 (0)