From d2f83f464a816b1c596444f91280559f3932c9ce Mon Sep 17 00:00:00 2001 From: Sean Sullivan Date: Wed, 30 Jun 2021 19:47:01 -0700 Subject: [PATCH] Changes Print interface to add PrintStatus boolean --- cmd/apply/cmdapply.go | 10 ++--- cmd/destroy/cmddestroy.go | 5 ++- cmd/preview/cmdpreview.go | 2 +- cmd/printers/events/formatter.go | 12 ++++-- cmd/printers/printer/printer.go | 2 +- cmd/printers/table/printer.go | 2 +- examples/alphaTestExamples/helloapp.md | 4 -- .../alphaTestExamples/inventoryNamespace.md | 1 - examples/alphaTestExamples/pruneBasic.md | 1 - examples/alphaTestExamples/pruneNamespace.md | 1 - pkg/print/list/base.go | 42 +++++++++---------- 11 files changed, 41 insertions(+), 41 deletions(-) diff --git a/cmd/apply/cmdapply.go b/cmd/apply/cmdapply.go index c517be9a..759b43b6 100644 --- a/cmd/apply/cmdapply.go +++ b/cmd/apply/cmdapply.go @@ -97,13 +97,13 @@ func (r *ApplyRunner) RunE(cmd *cobra.Command, args []string) error { return err } - // Only emit status events if we are waiting for status. + // Only print status events if we are waiting for status. //TODO: This is not the right way to do this. There are situations where // we do need status events event if we are not waiting for status. The // printers should be updated to handle this. - var emitStatusEvents bool + var printStatusEvents bool if r.reconcileTimeout != time.Duration(0) || r.pruneTimeout != time.Duration(0) { - emitStatusEvents = true + printStatusEvents = true } // TODO: Fix DemandOneDirectory to no longer return FileNameFlags @@ -153,7 +153,7 @@ func (r *ApplyRunner) RunE(cmd *cobra.Command, args []string) error { ReconcileTimeout: r.reconcileTimeout, // If we are not waiting for status, tell the applier to not // emit the events. - EmitStatusEvents: emitStatusEvents, + EmitStatusEvents: printStatusEvents, NoPrune: r.noPrune, DryRunStrategy: common.DryRunNone, PrunePropagationPolicy: prunePropPolicy, @@ -164,5 +164,5 @@ func (r *ApplyRunner) RunE(cmd *cobra.Command, args []string) error { // The printer will print updates from the channel. It will block // until the channel is closed. printer := printers.GetPrinter(r.output, r.ioStreams) - return printer.Print(ch, common.DryRunNone) + return printer.Print(ch, common.DryRunNone, printStatusEvents) } diff --git a/cmd/destroy/cmddestroy.go b/cmd/destroy/cmddestroy.go index 53bb5e93..6935aa28 100644 --- a/cmd/destroy/cmddestroy.go +++ b/cmd/destroy/cmddestroy.go @@ -116,15 +116,16 @@ func (r *DestroyRunner) RunE(cmd *cobra.Command, args []string) error { } // Run the destroyer. It will return a channel where we can receive updates // to keep track of progress and any issues. + printStatusEvents := r.deleteTimeout != time.Duration(0) ch := d.Run(inv, apply.DestroyerOptions{ DeleteTimeout: r.deleteTimeout, DeletePropagationPolicy: deletePropPolicy, InventoryPolicy: inventoryPolicy, - EmitStatusEvents: r.deleteTimeout != time.Duration(0), + EmitStatusEvents: printStatusEvents, }) // The printer will print updates from the channel. It will block // until the channel is closed. printer := printers.GetPrinter(r.output, r.ioStreams) - return printer.Print(ch, common.DryRunNone) + return printer.Print(ch, common.DryRunNone, printStatusEvents) } diff --git a/cmd/preview/cmdpreview.go b/cmd/preview/cmdpreview.go index 8805e573..fe404a3a 100644 --- a/cmd/preview/cmdpreview.go +++ b/cmd/preview/cmdpreview.go @@ -165,5 +165,5 @@ func (r *PreviewRunner) RunE(cmd *cobra.Command, args []string) error { // The printer will print updates from the channel. It will block // until the channel is closed. printer := printers.GetPrinter(r.output, r.ioStreams) - return printer.Print(ch, drs) + return printer.Print(ch, drs, false) // Do not print status } diff --git a/cmd/printers/events/formatter.go b/cmd/printers/events/formatter.go index 90b60506..423286b9 100644 --- a/cmd/printers/events/formatter.go +++ b/cmd/printers/events/formatter.go @@ -88,7 +88,9 @@ func (ef *formatter) FormatErrorEvent(_ event.ErrorEvent) error { func (ef *formatter) FormatActionGroupEvent(age event.ActionGroupEvent, ags []event.ActionGroup, as *list.ApplyStats, ps *list.PruneStats, ds *list.DeleteStats, c list.Collector) error { - if age.Action == event.ApplyAction && age.Type == event.Finished { + if age.Action == event.ApplyAction && + age.Type == event.Finished && + list.IsLastActionGroup(age, ags) { 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 @@ -99,11 +101,15 @@ func (ef *formatter) FormatActionGroupEvent(age event.ActionGroupEvent, ags []ev ef.print(output) } - if age.Action == event.PruneAction && age.Type == event.Finished { + if age.Action == event.PruneAction && + age.Type == event.Finished && + list.IsLastActionGroup(age, ags) { ef.print("%d resource(s) pruned, %d skipped, %d failed", ps.Pruned, ps.Skipped, ps.Failed) } - if age.Action == event.DeleteAction && age.Type == event.Finished { + if age.Action == event.DeleteAction && + age.Type == event.Finished && + list.IsLastActionGroup(age, ags) { ef.print("%d resource(s) deleted, %d skipped", ds.Deleted, ds.Skipped) } diff --git a/cmd/printers/printer/printer.go b/cmd/printers/printer/printer.go index 0310fd62..98428085 100644 --- a/cmd/printers/printer/printer.go +++ b/cmd/printers/printer/printer.go @@ -9,5 +9,5 @@ import ( ) type Printer interface { - Print(ch <-chan event.Event, previewStrategy common.DryRunStrategy) error + Print(ch <-chan event.Event, previewStrategy common.DryRunStrategy, printStatus bool) error } diff --git a/cmd/printers/table/printer.go b/cmd/printers/table/printer.go index 45f536af..e33cb19f 100644 --- a/cmd/printers/table/printer.go +++ b/cmd/printers/table/printer.go @@ -18,7 +18,7 @@ type Printer struct { IOStreams genericclioptions.IOStreams } -func (t *Printer) Print(ch <-chan event.Event, _ common.DryRunStrategy) error { +func (t *Printer) Print(ch <-chan event.Event, _ common.DryRunStrategy, printStatus bool) error { // Wait for the init event that will give us the set of // resources. var initEvent event.InitEvent diff --git a/examples/alphaTestExamples/helloapp.md b/examples/alphaTestExamples/helloapp.md index 7bd1a67f..55092545 100644 --- a/examples/alphaTestExamples/helloapp.md +++ b/examples/alphaTestExamples/helloapp.md @@ -209,10 +209,6 @@ rm $BASE/configMap.yaml kapply apply $BASE --reconcile-timeout=120s > $OUTPUT/status; -expectedOutputLine "deployment.apps/the-deployment is Current: Deployment is available. Replicas: 3" - -expectedOutputLine "service/the-service is Current: Service is ready" - expectedOutputLine "configmap/the-map2 is Current: Resource is always ready" expectedOutputLine "configmap/the-map1 pruned" diff --git a/examples/alphaTestExamples/inventoryNamespace.md b/examples/alphaTestExamples/inventoryNamespace.md index 42063d7d..898cdd12 100644 --- a/examples/alphaTestExamples/inventoryNamespace.md +++ b/examples/alphaTestExamples/inventoryNamespace.md @@ -89,7 +89,6 @@ kapply apply $BASE --reconcile-timeout=1m > $OUTPUT/status expectedOutputLine "namespace/test-namespace unchanged" expectedOutputLine "configmap/cm-a created" expectedOutputLine "2 resource(s) applied. 1 created, 1 unchanged, 0 configured" -expectedOutputLine "0 resource(s) pruned, 0 skipped" # There should be only one inventory object kubectl get cm -n test-namespace --selector='cli-utils.sigs.k8s.io/inventory-id' --no-headers | wc -l > $OUTPUT/status diff --git a/examples/alphaTestExamples/pruneBasic.md b/examples/alphaTestExamples/pruneBasic.md index adc4f994..e0bdb8ed 100644 --- a/examples/alphaTestExamples/pruneBasic.md +++ b/examples/alphaTestExamples/pruneBasic.md @@ -98,7 +98,6 @@ kapply apply $BASE --reconcile-timeout=1m > $OUTPUT/status expectedOutputLine "configmap/cm-a created" expectedOutputLine "configmap/cm-b created" expectedOutputLine "configmap/cm-c created" -expectedOutputLine "0 resource(s) pruned, 0 skipped" # There should be only one inventory object kubectl get cm --selector='cli-utils.sigs.k8s.io/inventory-id' --no-headers | wc -l > $OUTPUT/status diff --git a/examples/alphaTestExamples/pruneNamespace.md b/examples/alphaTestExamples/pruneNamespace.md index 53a12e72..45c56f78 100644 --- a/examples/alphaTestExamples/pruneNamespace.md +++ b/examples/alphaTestExamples/pruneNamespace.md @@ -114,7 +114,6 @@ expectedOutputLine "configmap/cm-a created" expectedOutputLine "configmap/cm-b created" expectedOutputLine "configmap/cm-c created" expectedOutputLine "4 resource(s) applied. 4 created, 0 unchanged, 0 configured" -expectedOutputLine "0 resource(s) pruned, 0 skipped" # There should be only one inventory object kubectl get cm --selector='cli-utils.sigs.k8s.io/inventory-id' --no-headers | wc -l > $OUTPUT/status diff --git a/pkg/print/list/base.go b/pkg/print/list/base.go index 250dc135..464bf40c 100644 --- a/pkg/print/list/base.go +++ b/pkg/print/list/base.go @@ -115,7 +115,7 @@ func (sc *StatusCollector) LatestStatus() map[object.ObjMetadata]event.StatusEve // this should probably be an interface. // This function will block until the channel is closed. //nolint:gocyclo -func (b *BaseListPrinter) Print(ch <-chan event.Event, previewStrategy common.DryRunStrategy) error { +func (b *BaseListPrinter) Print(ch <-chan event.Event, previewStrategy common.DryRunStrategy, printStatus bool) error { var actionGroups []event.ActionGroup applyStats := &ApplyStats{} pruneStats := &PruneStats{} @@ -123,7 +123,6 @@ func (b *BaseListPrinter) Print(ch <-chan event.Event, previewStrategy common.Dr statusCollector := &StatusCollector{ latestStatus: make(map[object.ObjMetadata]event.StatusEvent), } - printStatus := false formatter := b.FormatterFactory(previewStrategy) for e := range ch { switch e.Type { @@ -178,25 +177,6 @@ func (b *BaseListPrinter) Print(ch <-chan event.Event, previewStrategy common.Dr pruneStats, deleteStats, statusCollector); err != nil { return err } - - switch e.ActionGroupEvent.Action { - case event.ApplyAction: - if e.ActionGroupEvent.Type == event.Started { - applyStats = &ApplyStats{} - } - case event.PruneAction: - if e.ActionGroupEvent.Type == event.Started { - pruneStats = &PruneStats{} - } - case event.DeleteAction: - if e.ActionGroupEvent.Type == event.Started { - deleteStats = &DeleteStats{} - } - case event.WaitAction: - if e.ActionGroupEvent.Type == event.Started { - printStatus = true - } - } } } failedSum := applyStats.Failed + pruneStats.Failed + deleteStats.Failed @@ -214,3 +194,23 @@ func ActionGroupByName(name string, ags []event.ActionGroup) (event.ActionGroup, } return event.ActionGroup{}, false } + +// IsLastActionGroup returns true if the passed ActionGroupEvent is the +// last of its type in the slice of ActionGroup; false otherwise. For example, +// this function will determine if an ApplyAction is the last ApplyAction in +// the initialized task queue. This functionality is current used to determine +// when to print stats. +func IsLastActionGroup(age event.ActionGroupEvent, ags []event.ActionGroup) bool { + var found bool + var action event.ResourceAction + for _, ag := range ags { + if found && (action == ag.Action) { + return false + } + if age.GroupName == ag.Name { + found = true + action = age.Action + } + } + return true +}