diff --git a/cmd/printers/events/formatter.go b/cmd/printers/events/formatter.go index 79fe690..8a08cf6 100644 --- a/cmd/printers/events/formatter.go +++ b/cmd/printers/events/formatter.go @@ -32,8 +32,8 @@ type formatter struct { func (ef *formatter) FormatApplyEvent(ae event.ApplyEvent, as *list.ApplyStats, c list.Collector) error { switch ae.Type { case event.ApplyEventCompleted: - output := fmt.Sprintf("%d resource(s) applied. %d created, %d unchanged, %d configured", - as.Sum(), as.Created, as.Unchanged, as.Configured) + output := fmt.Sprintf("%d resource(s) applied. %d created, %d unchanged, %d configured, %d failed", + as.Sum(), as.Created, as.Unchanged, as.Configured, as.Failed) // Only print information about serverside apply if some of the // resources actually were applied serverside. if as.ServersideApplied > 0 { @@ -44,10 +44,9 @@ func (ef *formatter) FormatApplyEvent(ae event.ApplyEvent, as *list.ApplyStats, ef.printResourceStatus(id, se) } case event.ApplyEventResourceUpdate: - obj := ae.Object - gvk := obj.GetObjectKind().GroupVersionKind() - name := getName(obj) - ef.print("%s %s", resourceIDToString(gvk.GroupKind(), name), + gk := ae.Identifier.GroupKind + name := ae.Identifier.Name + ef.print("%s %s", resourceIDToString(gk, name), strings.ToLower(ae.Operation.String())) } return nil @@ -64,17 +63,17 @@ func (ef *formatter) FormatStatusEvent(se event.StatusEvent, _ list.Collector) e func (ef *formatter) FormatPruneEvent(pe event.PruneEvent, ps *list.PruneStats) error { switch pe.Type { case event.PruneEventCompleted: - ef.print("%d resource(s) pruned, %d skipped", ps.Pruned, ps.Skipped) + ef.print("%d resource(s) pruned, %d skipped, %d failed", ps.Pruned, ps.Skipped, ps.Failed) case event.PruneEventResourceUpdate: - obj := pe.Object - gvk := obj.GetObjectKind().GroupVersionKind() - name := getName(obj) + gk := pe.Identifier.GroupKind switch pe.Operation { case event.Pruned: - ef.print("%s %s", resourceIDToString(gvk.GroupKind(), name), "pruned") + ef.print("%s %s", resourceIDToString(gk, pe.Identifier.Name), "pruned") case event.PruneSkipped: - ef.print("%s %s", resourceIDToString(gvk.GroupKind(), name), "prune skipped") + ef.print("%s %s", resourceIDToString(gk, pe.Identifier.Name), "prune skipped") } + case event.PruneEventFailed: + ef.print("%s %s", resourceIDToString(pe.Identifier.GroupKind, pe.Identifier.Name), "prune failed") } return nil } diff --git a/cmd/printers/events/formatter_test.go b/cmd/printers/events/formatter_test.go index 66a09d9..66252a1 100644 --- a/cmd/printers/events/formatter_test.go +++ b/cmd/printers/events/formatter_test.go @@ -31,27 +31,27 @@ func TestFormatter_FormatApplyEvent(t *testing.T) { "resource created without no dryrun": { previewStrategy: common.DryRunNone, event: event.ApplyEvent{ - Operation: event.Created, - Type: event.ApplyEventResourceUpdate, - Object: createObject("apps", "Deployment", "default", "my-dep"), + Operation: event.Created, + Type: event.ApplyEventResourceUpdate, + Identifier: createIdentifier("apps", "Deployment", "default", "my-dep"), }, expected: "deployment.apps/my-dep created", }, "resource updated with client dryrun": { previewStrategy: common.DryRunClient, event: event.ApplyEvent{ - Operation: event.Configured, - Type: event.ApplyEventResourceUpdate, - Object: createObject("apps", "Deployment", "", "my-dep"), + Operation: event.Configured, + Type: event.ApplyEventResourceUpdate, + Identifier: createIdentifier("apps", "Deployment", "", "my-dep"), }, expected: "deployment.apps/my-dep configured (preview)", }, "resource updated with server dryrun": { previewStrategy: common.DryRunServer, event: event.ApplyEvent{ - Operation: event.Configured, - Type: event.ApplyEventResourceUpdate, - Object: createObject("batch", "CronJob", "foo", "my-cron"), + Operation: event.Configured, + Type: event.ApplyEventResourceUpdate, + Identifier: createIdentifier("batch", "CronJob", "foo", "my-cron"), }, expected: "cronjob.batch/my-cron configured (preview-server)", }, @@ -81,7 +81,7 @@ func TestFormatter_FormatApplyEvent(t *testing.T) { }, }, expected: ` -1 resource(s) applied. 0 created, 0 unchanged, 0 configured, 1 serverside applied +1 resource(s) applied. 0 created, 0 unchanged, 0 configured, 0 failed, 1 serverside applied deployment.apps/my-dep is Current: Resource is Current `, }, @@ -149,18 +149,18 @@ func TestFormatter_FormatPruneEvent(t *testing.T) { "resource pruned without no dryrun": { previewStrategy: common.DryRunNone, event: event.PruneEvent{ - Operation: event.Pruned, - Type: event.PruneEventResourceUpdate, - Object: createObject("apps", "Deployment", "default", "my-dep"), + Operation: event.Pruned, + Type: event.PruneEventResourceUpdate, + Identifier: createIdentifier("apps", "Deployment", "default", "my-dep"), }, expected: "deployment.apps/my-dep pruned", }, "resource skipped with client dryrun": { previewStrategy: common.DryRunClient, event: event.PruneEvent{ - Operation: event.PruneSkipped, - Type: event.PruneEventResourceUpdate, - Object: createObject("apps", "Deployment", "", "my-dep"), + Operation: event.PruneSkipped, + Type: event.PruneEventResourceUpdate, + Identifier: createIdentifier("apps", "Deployment", "", "my-dep"), }, expected: "deployment.apps/my-dep prune skipped (preview)", }, @@ -173,7 +173,7 @@ func TestFormatter_FormatPruneEvent(t *testing.T) { Pruned: 1, Skipped: 2, }, - expected: "1 resource(s) pruned, 2 skipped", + expected: "1 resource(s) pruned, 2 skipped, 0 failed", }, } @@ -253,6 +253,17 @@ func createObject(group, kind, namespace, name string) *unstructured.Unstructure } } +func createIdentifier(group, kind, namespace, name string) object.ObjMetadata { + return object.ObjMetadata{ + Namespace: namespace, + Name: name, + GroupKind: schema.GroupKind{ + Group: group, + Kind: kind, + }, + } +} + type fakeCollector struct { m map[object.ObjMetadata]event.StatusEvent } diff --git a/cmd/printers/json/formatter.go b/cmd/printers/json/formatter.go index 9df36c5..aa2aca6 100644 --- a/cmd/printers/json/formatter.go +++ b/cmd/printers/json/formatter.go @@ -8,8 +8,6 @@ import ( "fmt" "time" - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/cli-runtime/pkg/genericclioptions" "sigs.k8s.io/cli-utils/pkg/apply/event" "sigs.k8s.io/cli-utils/pkg/common" @@ -39,6 +37,7 @@ func (jf *formatter) FormatApplyEvent(ae event.ApplyEvent, as *list.ApplyStats, "unchangedCount": as.Unchanged, "configuredCount": as.Configured, "serverSideCount": as.ServersideApplied, + "failedCount": as.Failed, }); err != nil { return err } @@ -49,13 +48,12 @@ func (jf *formatter) FormatApplyEvent(ae event.ApplyEvent, as *list.ApplyStats, } } case event.ApplyEventResourceUpdate: - obj := ae.Object - gvk := obj.GetObjectKind().GroupVersionKind() + gk := ae.Identifier.GroupKind return jf.printEvent("apply", "resourceApplied", map[string]interface{}{ - "group": gvk.Group, - "kind": gvk.Kind, - "namespace": getNamespace(obj), - "name": getName(obj), + "group": gk.Group, + "kind": gk.Kind, + "namespace": ae.Identifier.Namespace, + "name": ae.Identifier.Name, "operation": ae.Operation.String(), }) } @@ -90,15 +88,23 @@ func (jf *formatter) FormatPruneEvent(pe event.PruneEvent, ps *list.PruneStats) "skipped": ps.Skipped, }) case event.PruneEventResourceUpdate: - obj := pe.Object - gvk := obj.GetObjectKind().GroupVersionKind() + gk := pe.Identifier.GroupKind return jf.printEvent("prune", "resourcePruned", map[string]interface{}{ - "group": gvk.Group, - "kind": gvk.Kind, - "namespace": getNamespace(obj), - "name": getName(obj), + "group": gk.Group, + "kind": gk.Kind, + "namespace": pe.Identifier.Namespace, + "name": pe.Identifier.Name, "operation": pe.Operation.String(), }) + case event.PruneEventFailed: + gk := pe.Identifier.GroupKind + return jf.printEvent("prune", "resourceFailed", map[string]interface{}{ + "group": gk.Group, + "kind": gk.Kind, + "namespace": pe.Identifier.Namespace, + "name": pe.Identifier.Name, + "error": pe.Error.Error(), + }) } return nil } @@ -111,15 +117,23 @@ func (jf *formatter) FormatDeleteEvent(de event.DeleteEvent, ds *list.DeleteStat "skipped": ds.Skipped, }) case event.DeleteEventResourceUpdate: - obj := de.Object - gvk := obj.GetObjectKind().GroupVersionKind() + gk := de.Identifier.GroupKind return jf.printEvent("delete", "resourceDeleted", map[string]interface{}{ - "group": gvk.Group, - "kind": gvk.Kind, - "namespace": getNamespace(obj), - "name": getName(obj), + "group": gk.Group, + "kind": gk.Kind, + "namespace": de.Identifier.Namespace, + "name": de.Identifier.Name, "operation": de.Operation.String(), }) + case event.DeleteEventFailed: + gk := de.Identifier.GroupKind + return jf.printEvent("delete", "resourceFailed", map[string]interface{}{ + "group": gk.Group, + "kind": gk.Kind, + "namespace": de.Identifier.Namespace, + "name": de.Identifier.Name, + "error": de.Error.Error(), + }) } return nil } @@ -145,13 +159,3 @@ func (jf *formatter) printEvent(t, eventType string, content map[string]interfac _, err = fmt.Fprint(jf.ioStreams.Out, string(b)+"\n") return err } - -func getName(obj runtime.Object) string { - acc, _ := meta.Accessor(obj) - return acc.GetName() -} - -func getNamespace(obj runtime.Object) string { - acc, _ := meta.Accessor(obj) - return acc.GetNamespace() -} diff --git a/cmd/printers/json/formatter_test.go b/cmd/printers/json/formatter_test.go index ace58ee..80110e9 100644 --- a/cmd/printers/json/formatter_test.go +++ b/cmd/printers/json/formatter_test.go @@ -5,12 +5,10 @@ package json import ( "encoding/json" - "fmt" "strings" "testing" "github.com/stretchr/testify/assert" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/cli-runtime/pkg/genericclioptions" "sigs.k8s.io/cli-utils/pkg/apply/event" @@ -32,9 +30,9 @@ func TestFormatter_FormatApplyEvent(t *testing.T) { "resource created without dryrun": { previewStrategy: common.DryRunNone, event: event.ApplyEvent{ - Operation: event.Created, - Type: event.ApplyEventResourceUpdate, - Object: createObject("apps", "Deployment", "default", "my-dep"), + Operation: event.Created, + Type: event.ApplyEventResourceUpdate, + Identifier: createIdentifier("apps", "Deployment", "default", "my-dep"), }, expected: []map[string]interface{}{ { @@ -52,9 +50,9 @@ func TestFormatter_FormatApplyEvent(t *testing.T) { "resource updated with client dryrun": { previewStrategy: common.DryRunClient, event: event.ApplyEvent{ - Operation: event.Configured, - Type: event.ApplyEventResourceUpdate, - Object: createObject("apps", "Deployment", "", "my-dep"), + Operation: event.Configured, + Type: event.ApplyEventResourceUpdate, + Identifier: createIdentifier("apps", "Deployment", "", "my-dep"), }, expected: []map[string]interface{}{ { @@ -72,9 +70,9 @@ func TestFormatter_FormatApplyEvent(t *testing.T) { "resource updated with server dryrun": { previewStrategy: common.DryRunServer, event: event.ApplyEvent{ - Operation: event.Configured, - Type: event.ApplyEventResourceUpdate, - Object: createObject("batch", "CronJob", "foo", "my-cron"), + Operation: event.Configured, + Type: event.ApplyEventResourceUpdate, + Identifier: createIdentifier("batch", "CronJob", "foo", "my-cron"), }, expected: []map[string]interface{}{ { @@ -120,6 +118,7 @@ func TestFormatter_FormatApplyEvent(t *testing.T) { "count": 1, "createdCount": 0, "eventType": "completed", + "failedCount": 0, "serverSideCount": 1, "type": "apply", "unchangedCount": 0, @@ -219,9 +218,9 @@ func TestFormatter_FormatPruneEvent(t *testing.T) { "resource pruned without dryrun": { previewStrategy: common.DryRunNone, event: event.PruneEvent{ - Operation: event.Pruned, - Type: event.PruneEventResourceUpdate, - Object: createObject("apps", "Deployment", "default", "my-dep"), + Operation: event.Pruned, + Type: event.PruneEventResourceUpdate, + Identifier: createIdentifier("apps", "Deployment", "default", "my-dep"), }, expected: map[string]interface{}{ "eventType": "resourcePruned", @@ -237,9 +236,9 @@ func TestFormatter_FormatPruneEvent(t *testing.T) { "resource skipped with client dryrun": { previewStrategy: common.DryRunClient, event: event.PruneEvent{ - Operation: event.PruneSkipped, - Type: event.PruneEventResourceUpdate, - Object: createObject("apps", "Deployment", "", "my-dep"), + Operation: event.PruneSkipped, + Type: event.PruneEventResourceUpdate, + Identifier: createIdentifier("apps", "Deployment", "", "my-dep"), }, expected: map[string]interface{}{ "eventType": "resourcePruned", @@ -294,9 +293,9 @@ func TestFormatter_FormatDeleteEvent(t *testing.T) { "resource deleted without no dryrun": { previewStrategy: common.DryRunNone, event: event.DeleteEvent{ - Operation: event.Deleted, - Type: event.DeleteEventResourceUpdate, - Object: createObject("apps", "Deployment", "default", "my-dep"), + Operation: event.Deleted, + Type: event.DeleteEventResourceUpdate, + Identifier: createIdentifier("apps", "Deployment", "default", "my-dep"), }, expected: map[string]interface{}{ "eventType": "resourceDeleted", @@ -312,9 +311,9 @@ func TestFormatter_FormatDeleteEvent(t *testing.T) { "resource skipped with client dryrun": { previewStrategy: common.DryRunClient, event: event.DeleteEvent{ - Operation: event.DeleteSkipped, - Type: event.DeleteEventResourceUpdate, - Object: createObject("apps", "Deployment", "", "my-dep"), + Operation: event.DeleteSkipped, + Type: event.DeleteEventResourceUpdate, + Identifier: createIdentifier("apps", "Deployment", "", "my-dep"), }, expected: map[string]interface{}{ "eventType": "resourceDeleted", @@ -385,15 +384,13 @@ func assertOutput(t *testing.T, expectedMap map[string]interface{}, actual strin return assert.Equal(t, expectedMap, m) } -func createObject(group, kind, namespace, name string) *unstructured.Unstructured { - return &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": fmt.Sprintf("%s/v1", group), - "kind": kind, - "metadata": map[string]interface{}{ - "name": name, - "namespace": namespace, - }, +func createIdentifier(group, kind, namespace, name string) object.ObjMetadata { + return object.ObjMetadata{ + Namespace: namespace, + Name: name, + GroupKind: schema.GroupKind{ + Group: group, + Kind: kind, }, } } diff --git a/cmd/printers/table/collector.go b/cmd/printers/table/collector.go index dc7dafd..1f666b5 100644 --- a/cmd/printers/table/collector.go +++ b/cmd/printers/table/collector.go @@ -7,8 +7,6 @@ import ( "sort" "sync" - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/cli-utils/pkg/apply/event" pe "sigs.k8s.io/cli-utils/pkg/kstatus/polling/event" "sigs.k8s.io/cli-utils/pkg/kstatus/status" @@ -193,7 +191,7 @@ func (r *ResourceStateCollector) processStatusEvent(e event.StatusEvent) { // processApplyEvent handles events relating to apply operations func (r *ResourceStateCollector) processApplyEvent(e event.ApplyEvent) { if e.Type == event.ApplyEventResourceUpdate { - identifier := toIdentifier(e.Object) + identifier := e.Identifier previous, found := r.resourceInfos[identifier] if !found { return @@ -205,7 +203,7 @@ func (r *ResourceStateCollector) processApplyEvent(e event.ApplyEvent) { // processPruneEvent handles event related to prune operations. func (r *ResourceStateCollector) processPruneEvent(e event.PruneEvent) { if e.Type == event.PruneEventResourceUpdate { - identifier := toIdentifier(e.Object) + identifier := e.Identifier previous, found := r.resourceInfos[identifier] if !found { return @@ -214,17 +212,6 @@ func (r *ResourceStateCollector) processPruneEvent(e event.PruneEvent) { } } -// toIdentifier extracts the identifying information from an -// object. -func toIdentifier(o runtime.Object) object.ObjMetadata { - accessor, _ := meta.Accessor(o) - return object.ObjMetadata{ - GroupKind: o.GetObjectKind().GroupVersionKind().GroupKind(), - Namespace: accessor.GetNamespace(), - Name: accessor.GetName(), - } -} - // ResourceState contains the latest state for all the resources. type ResourceState struct { resourceInfos ResourceInfos diff --git a/examples/alphaTestExamples/helloapp.md b/examples/alphaTestExamples/helloapp.md index 45b7fac..212ba63 100644 --- a/examples/alphaTestExamples/helloapp.md +++ b/examples/alphaTestExamples/helloapp.md @@ -163,11 +163,11 @@ Run preview to check which commands will be executed ``` kapply preview $BASE > $OUTPUT/status -expectedOutputLine "3 resource(s) applied. 3 created, 0 unchanged, 0 configured (preview)" +expectedOutputLine "3 resource(s) applied. 3 created, 0 unchanged, 0 configured, 0 failed (preview)" kapply preview $BASE --server-side > $OUTPUT/status -expectedOutputLine "3 resource(s) applied. 0 created, 0 unchanged, 0 configured, 3 serverside applied (preview-server)" +expectedOutputLine "3 resource(s) applied. 0 created, 0 unchanged, 0 configured, 0 failed, 3 serverside applied (preview-server)" # Verify that preview didn't create any resources. kubectl get all -n hellospace > $OUTPUT/status 2>&1 diff --git a/go.sum b/go.sum index 83da167..4a5db3a 100644 --- a/go.sum +++ b/go.sum @@ -706,8 +706,6 @@ sigs.k8s.io/controller-runtime v0.6.0 h1:Fzna3DY7c4BIP6KwfSlrfnj20DJ+SeMBK8HSFvO sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo= sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= -sigs.k8s.io/kustomize/kyaml v0.9.4 h1:DDuzZtjIzFqp2IPy4DTyCI69Cl3bDgcJODjI6sjF9NY= -sigs.k8s.io/kustomize/kyaml v0.9.4/go.mod h1:UTm64bSWVdBUA8EQoYCxVOaBQxUdIOr5LKWxA4GNbkw= sigs.k8s.io/kustomize/kyaml v0.10.3 h1:ARSJUMN/c3k31DYxRfZ+vp/UepUQjg9zCwny7Oj908I= sigs.k8s.io/kustomize/kyaml v0.10.3/go.mod h1:RA+iCHA2wPCOfv6uG6TfXXWhYsHpgErq/AljxWKuxtg= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= diff --git a/pkg/apply/event/applyeventoperation_string.go b/pkg/apply/event/applyeventoperation_string.go index 50ff42f..58642b4 100644 --- a/pkg/apply/event/applyeventoperation_string.go +++ b/pkg/apply/event/applyeventoperation_string.go @@ -15,11 +15,12 @@ func _() { _ = x[Created-1] _ = x[Unchanged-2] _ = x[Configured-3] + _ = x[Failed-4] } -const _ApplyEventOperation_name = "ServersideAppliedCreatedUnchangedConfigured" +const _ApplyEventOperation_name = "ServersideAppliedCreatedUnchangedConfiguredFailed" -var _ApplyEventOperation_index = [...]uint8{0, 17, 24, 33, 43} +var _ApplyEventOperation_index = [...]uint8{0, 17, 24, 33, 43, 49} func (i ApplyEventOperation) String() string { if i < 0 || i >= ApplyEventOperation(len(_ApplyEventOperation_index)-1) { diff --git a/pkg/apply/event/event.go b/pkg/apply/event/event.go index 6b78376..29ff720 100644 --- a/pkg/apply/event/event.go +++ b/pkg/apply/event/event.go @@ -91,6 +91,7 @@ const ( Created Unchanged Configured + Failed ) type ApplyEvent struct { diff --git a/pkg/apply/task/apply_task.go b/pkg/apply/task/apply_task.go index 4388eda..d107919 100644 --- a/pkg/apply/task/apply_task.go +++ b/pkg/apply/task/apply_task.go @@ -113,7 +113,7 @@ func (a *ApplyTask) Start(taskContext *taskrunner.TaskContext) { info, err := a.InfoHelper.BuildInfo(obj) if err != nil { taskContext.EventChannel() <- createApplyEvent( - object.UnstructuredToObjMeta(obj), event.Unchanged, applyerror.NewUnknownTypeError(err)) + object.UnstructuredToObjMeta(obj), event.Failed, applyerror.NewUnknownTypeError(err)) continue } infos = append(infos, info) @@ -121,7 +121,7 @@ func (a *ApplyTask) Start(taskContext *taskrunner.TaskContext) { err = ao.Run() if err != nil { taskContext.EventChannel() <- createApplyEvent( - object.UnstructuredToObjMeta(obj), event.Unchanged, applyerror.NewApplyRunError(err)) + object.UnstructuredToObjMeta(obj), event.Failed, applyerror.NewApplyRunError(err)) } } @@ -296,6 +296,6 @@ func createApplyEvent(id object.ObjMetadata, operation event.ApplyEventOperation func sendBatchApplyEvents(taskContext *taskrunner.TaskContext, objects []*unstructured.Unstructured, err error) { for _, obj := range objects { taskContext.EventChannel() <- createApplyEvent( - object.UnstructuredToObjMeta(obj), event.Unchanged, applyerror.NewInitializeApplyOptionError(err)) + object.UnstructuredToObjMeta(obj), event.Failed, applyerror.NewInitializeApplyOptionError(err)) } } diff --git a/pkg/print/list/base.go b/pkg/print/list/base.go index 03a9f49..e7c0460 100644 --- a/pkg/print/list/base.go +++ b/pkg/print/list/base.go @@ -33,6 +33,7 @@ type ApplyStats struct { Created int Unchanged int Configured int + Failed int } func (a *ApplyStats) inc(op event.ApplyEventOperation) { @@ -45,18 +46,21 @@ func (a *ApplyStats) inc(op event.ApplyEventOperation) { a.Unchanged++ case event.Configured: a.Configured++ + case event.Failed: + a.Failed++ default: panic(fmt.Errorf("unknown apply operation %s", op.String())) } } func (a *ApplyStats) Sum() int { - return a.ServersideApplied + a.Configured + a.Unchanged + a.Created + return a.ServersideApplied + a.Configured + a.Unchanged + a.Created + a.Failed } type PruneStats struct { Pruned int Skipped int + Failed int } func (p *PruneStats) incPruned() { @@ -67,9 +71,14 @@ func (p *PruneStats) incSkipped() { p.Skipped++ } +func (p *PruneStats) incFailed() { + p.Failed++ +} + type DeleteStats struct { Deleted int Skipped int + Failed int } func (d *DeleteStats) incDeleted() { @@ -80,6 +89,10 @@ func (d *DeleteStats) incSkipped() { d.Skipped++ } +func (d *DeleteStats) incFailed() { + d.Failed++ +} + type Collector interface { LatestStatus() map[object.ObjMetadata]event.StatusEvent } @@ -142,6 +155,9 @@ func (b *BaseListPrinter) Print(ch <-chan event.Event, previewStrategy common.Dr pruneStats.incSkipped() } } + if e.PruneEvent.Type == event.PruneEventFailed { + pruneStats.incFailed() + } if err := formatter.FormatPruneEvent(e.PruneEvent, pruneStats); err != nil { return err } @@ -154,6 +170,9 @@ func (b *BaseListPrinter) Print(ch <-chan event.Event, previewStrategy common.Dr deleteStats.incSkipped() } } + if e.DeleteEvent.Type == event.DeleteEventFailed { + deleteStats.incFailed() + } if err := formatter.FormatDeleteEvent(e.DeleteEvent, deleteStats); err != nil { return err }