fix(cli): add retention to JSON output (#1992)

refactor(cli): snapshot list JSON functionality.
Defines SnapshotManifest struct for the snapshot list JSON output.

test(cli): `snapshot list --json`
This commit is contained in:
Julio Lopez
2022-05-31 13:43:42 -07:00
committed by GitHub
parent 9167c08183
commit 99fb50118f
7 changed files with 123 additions and 40 deletions

View File

@@ -10,6 +10,7 @@
"github.com/stretchr/testify/require"
"github.com/kopia/kopia/cli"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo/content"
"github.com/kopia/kopia/repo/object"
@@ -334,7 +335,7 @@ func TestSnapshotFix(t *testing.T) {
env.RunAndExpectSuccess(t, "snapshot", "verify")
var manifests []snapshot.Manifest
var manifests []cli.SnapshotManifest
testutil.MustParseJSONLines(t, env.RunAndExpectSuccess(t, "snapshot", "list", "--json"), &manifests)
require.Len(t, manifests, 2)

View File

@@ -112,11 +112,6 @@ func findManifestIDs(ctx context.Context, rep repo.Repository, source string, ta
}
func (c *commandSnapshotList) run(ctx context.Context, rep repo.Repository) error {
var jl jsonList
jl.begin(&c.jo)
defer jl.end()
tags, err := getTags(c.snapshotListTags)
if err != nil {
return err
@@ -133,27 +128,54 @@ func (c *commandSnapshotList) run(ctx context.Context, rep repo.Repository) erro
}
if c.jo.jsonOutput {
for _, snapshotGroup := range snapshot.GroupBySource(manifests) {
snapshotGroup = snapshot.SortByTime(snapshotGroup, c.reverseSort)
if c.maxResultsPerPath > 0 && len(snapshotGroup) > c.maxResultsPerPath {
snapshotGroup = snapshotGroup[len(snapshotGroup)-c.maxResultsPerPath:]
}
if err := c.iterateSnapshotsMaybeWithStorageStats(ctx, rep, snapshotGroup, func(m *snapshot.Manifest) error {
jl.emit(m)
return nil
}); err != nil {
return errors.Wrap(err, "unable to iterate snapshots")
}
}
return nil
return c.outputJSON(ctx, rep, manifests)
}
return c.outputManifestGroups(ctx, rep, manifests, strings.Split(relPath, "/"))
}
// SnapshotManifest defines the JSON output for the CLI snapshot commands.
type SnapshotManifest struct {
*snapshot.Manifest
RetentionReasons []string `json:"retentionReason,omitempty"`
}
func (c *commandSnapshotList) outputJSON(ctx context.Context, rep repo.Repository, manifests []*snapshot.Manifest) error {
var jl jsonList
jl.begin(&c.jo)
defer jl.end()
for _, snapshotGroup := range snapshot.GroupBySource(manifests) {
snapshotGroup = snapshot.SortByTime(snapshotGroup, c.reverseSort)
if c.maxResultsPerPath > 0 && len(snapshotGroup) > c.maxResultsPerPath {
snapshotGroup = snapshotGroup[len(snapshotGroup)-c.maxResultsPerPath:]
}
if c.snapshotListShowRetentionReasons {
src := snapshotGroup[0].Source
// compute retention reason
pol, _, _, err := policy.GetEffectivePolicy(ctx, rep, src)
if err != nil {
log(ctx).Errorf("unable to determine effective policy for %v", src)
} else {
pol.RetentionPolicy.ComputeRetentionReasons(snapshotGroup)
}
}
if err := c.iterateSnapshotsMaybeWithStorageStats(ctx, rep, snapshotGroup, func(m *snapshot.Manifest) error {
wm := SnapshotManifest{Manifest: m, RetentionReasons: m.RetentionReasons}
jl.emit(wm)
return nil
}); err != nil {
return errors.Wrap(err, "unable to iterate snapshots")
}
}
return nil
}
func (c *commandSnapshotList) shouldOutputSnapshotSource(rep repo.Repository, src snapshot.SourceInfo) bool {
if c.snapshotListShowAll {
return true

View File

@@ -0,0 +1,50 @@
package cli_test
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"github.com/kopia/kopia/cli"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/tests/testenv"
)
func TestSnapshotList(t *testing.T) {
t.Parallel()
runner := testenv.NewInProcRunner(t)
e := testenv.NewCLITest(t, testenv.RepoFormatNotImportant, runner)
defer e.RunAndExpectSuccess(t, "repo", "disconnect")
e.RunAndExpectSuccess(t, "repo", "create", "filesystem", "--path", e.RepoDir)
srcdir := testutil.TempDirectory(t)
require.NoError(t, os.WriteFile(filepath.Join(srcdir, "some-file2"), []byte{1, 2, 3}, 0o755))
var man cli.SnapshotManifest
e.RunAndExpectSuccess(t, "policy", "set", srcdir, "--keep-latest=4", "--keep-hourly=0", "--keep-daily=0", "--keep-monthly=0", "--keep-weekly=0", "--keep-annual=0")
testutil.MustParseJSONLines(t, e.RunAndExpectSuccess(t, "snapshot", "create", srcdir, "--json"), &man)
require.NoError(t, os.WriteFile(filepath.Join(srcdir, "some-file3"), []byte{1, 2, 3, 4}, 0o755))
testutil.MustParseJSONLines(t, e.RunAndExpectSuccess(t, "snapshot", "create", srcdir, "--json"), &man)
require.NoError(t, os.WriteFile(filepath.Join(srcdir, "some-file4"), []byte{4}, 0o755))
e.RunAndExpectSuccess(t, "snapshot", "create", srcdir)
e.RunAndExpectSuccess(t, "snapshot", "create", srcdir)
var snapshots []*cli.SnapshotManifest
testutil.MustParseJSONLines(t, e.RunAndExpectSuccess(t, "snapshot", "list",
"--json"), &snapshots)
require.Len(t, snapshots, 4)
for _, s := range snapshots {
require.NotEmpty(t, s.RetentionReasons, "expecting retention reason to be set")
}
}

View File

@@ -7,6 +7,7 @@
"github.com/stretchr/testify/require"
"github.com/kopia/kopia/cli"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/snapshot"
"github.com/kopia/kopia/tests/testenv"
@@ -40,10 +41,7 @@ func TestSnapshotPin(t *testing.T) {
e.RunAndExpectSuccess(t, "snapshot", "create", srcdir)
e.RunAndExpectSuccess(t, "snapshot", "create", srcdir)
var snapshots []*snapshot.Manifest
testutil.MustParseJSONLines(t, e.RunAndExpectSuccess(t, "snapshot", "list", "--json"), &snapshots)
snapshots = snapshot.SortByTime(snapshots, false)
snapshots := mustListSnapshots(t, e)
// make sure the pinned one is on top.
require.Len(t, snapshots, 4)
@@ -57,12 +55,9 @@ func TestSnapshotPin(t *testing.T) {
e.RunAndExpectSuccess(t, "snapshot", "pin", string(snapshots[0].ID), "--add=c", "--remove=b")
e.RunAndExpectSuccess(t, "snapshot", "pin", string(snapshots[3].ID), "--add=d")
var snapshots2 []*snapshot.Manifest
snapshots2 := mustListSnapshots(t, e)
testutil.MustParseJSONLines(t, e.RunAndExpectSuccess(t, "snapshot", "list", "--json"), &snapshots2)
snapshots2 = snapshot.SortByTime(snapshots2, false)
require.Len(t, snapshots2, 4)
require.Equal(t, []string{"a", "c"}, snapshots2[0].Pins)
require.Empty(t, snapshots2[1].Pins)
require.Empty(t, snapshots2[2].Pins)
@@ -75,15 +70,28 @@ func TestSnapshotPin(t *testing.T) {
e.RunAndExpectSuccess(t, "snapshot", "create", srcdir)
e.RunAndExpectSuccess(t, "snapshot", "create", srcdir)
var snapshots3 []*snapshot.Manifest
snapshots3 := mustListSnapshots(t, e)
testutil.MustParseJSONLines(t, e.RunAndExpectSuccess(t, "snapshot", "list", "--json"), &snapshots3)
snapshots3 = snapshot.SortByTime(snapshots3, false)
require.Len(t, snapshots3, 5)
require.Equal(t, []string{"a", "c"}, snapshots3[0].Pins)
require.Equal(t, []string{"d"}, snapshots3[1].Pins)
require.Empty(t, snapshots3[2].Pins)
require.Empty(t, snapshots3[3].Pins)
require.Empty(t, snapshots3[4].Pins)
}
func mustListSnapshots(t *testing.T, e *testenv.CLITest) []*snapshot.Manifest {
t.Helper()
var cliSnapshots []cli.SnapshotManifest
testutil.MustParseJSONLines(t, e.RunAndExpectSuccess(t, "snapshot", "list", "--json"), &cliSnapshots)
snapshots := make([]*snapshot.Manifest, 0, len(cliSnapshots))
for _, s := range cliSnapshots {
snapshots = append(snapshots, s.Manifest)
}
return snapshot.SortByTime(snapshots, false)
}

View File

@@ -7,6 +7,7 @@
"github.com/stretchr/testify/require"
"github.com/kopia/kopia/cli"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/snapshot"
"github.com/kopia/kopia/tests/testenv"
@@ -31,7 +32,7 @@ func TestSnapshotStorageStats(t *testing.T) {
require.NoError(t, os.WriteFile(filepath.Join(dir1, "subdir", "file4.txt"), []byte{1, 2, 3, 4, 5, 6, 7, 8}, 0o600))
env.RunAndExpectSuccess(t, "snapshot", "create", dir1)
var manifests []*snapshot.Manifest
var manifests []cli.SnapshotManifest
testutil.MustParseJSONLines(t, env.RunAndExpectSuccess(t, "snapshot", "ls", "--storage-stats", dir1, "--json"), &manifests)
require.Len(t, manifests, 2)

View File

@@ -14,6 +14,7 @@
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
"github.com/kopia/kopia/cli"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo"
"github.com/kopia/kopia/snapshot"
@@ -54,12 +55,12 @@ func TestSnapshotCreate(t *testing.T) {
require.NotEqual(t, man1.ID, man2.ID)
require.Equal(t, man1.RootEntry.ObjectID, man2.RootEntry.ObjectID)
var manifests []snapshot.Manifest
var manifests []cli.SnapshotManifest
testutil.MustParseJSONLines(t, e.RunAndExpectSuccess(t, "snapshot", "list", "-a", "--json"), &manifests)
require.Len(t, manifests, 6)
var manifests2 []snapshot.Manifest
var manifests2 []cli.SnapshotManifest
testutil.MustParseJSONLines(t, e.RunAndExpectSuccess(t, "snapshot", "list", "-a", "--json", "--max-results=1"), &manifests2)
@@ -87,7 +88,7 @@ func TestTagging(t *testing.T) {
e.RunAndExpectSuccess(t, "snapshot", "create", sharedTestDataDir1, "--tags", "testkey1:testkey2")
e.RunAndExpectSuccess(t, "snapshot", "create", sharedTestDataDir1)
var manifests []snapshot.Manifest
var manifests []cli.SnapshotManifest
testutil.MustParseJSONLines(t, e.RunAndExpectSuccess(t, "snapshot", "list", "-a", "--json"), &manifests)

View File

@@ -8,8 +8,8 @@
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"github.com/kopia/kopia/cli"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/snapshot"
"github.com/kopia/kopia/tests/testenv"
)
@@ -90,7 +90,7 @@ func (s *formatSpecificTestSuite) TestSnapshotMigrateWithIgnores(t *testing.T) {
dstenv.RunAndExpectSuccess(t, "policy", "set", sd, "--add-ignore", "file2.txt")
dstenv.RunAndExpectSuccess(t, "snapshot", "migrate", "--source-config", filepath.Join(e.ConfigDir, ".kopia.config"), "--all", "--apply-ignore-rules")
var manifests []snapshot.Manifest
var manifests []cli.SnapshotManifest
testutil.MustParseJSONLines(t, dstenv.RunAndExpectSuccess(t, "snapshot", "list", "-a", sd, "--json"), &manifests)