Skip to content

Commit

Permalink
Remove printers from third_party and use cli-utils (#2627)
Browse files Browse the repository at this point in the history
  • Loading branch information
mortent committed Jan 11, 2022
1 parent 67521d1 commit 5eb30e0
Show file tree
Hide file tree
Showing 39 changed files with 113 additions and 3,057 deletions.
62 changes: 26 additions & 36 deletions e2e/live/end-to-end-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -437,11 +437,10 @@ ${BIN_DIR}/kpt live apply e2e/live/testdata/rg-test-case-1a > $OUTPUT_DIR/status
# The ResourceGroup inventory CRD is automatically installed on the initial apply.
assertContains "installing inventory ResourceGroup CRD"
assertContains "namespace/rg-test-namespace unchanged"
assertContains "1 resource(s) applied. 0 created, 1 unchanged, 0 configured, 0 failed"
assertContains "pod/pod-a created"
assertContains "pod/pod-b created"
assertContains "pod/pod-c created"
assertContains "3 resource(s) applied. 3 created, 0 unchanged, 0 configured, 0 failed"
assertContains "4 resource(s) applied. 3 created, 1 unchanged, 0 configured, 0 failed"
wait 2
# Validate resources in the cluster
# ConfigMap inventory with four inventory items.
Expand All @@ -451,11 +450,10 @@ assertRGInventory "rg-test-namespace" "4"
${BIN_DIR}/kpt live apply e2e/live/testdata/rg-test-case-1a > $OUTPUT_DIR/status 2>&1
assertNotContains "installing inventory ResourceGroup CRD" # Not applied again
assertContains "namespace/rg-test-namespace unchanged"
assertContains "1 resource(s) applied. 0 created, 1 unchanged, 0 configured, 0 failed"
assertContains "pod/pod-a unchanged"
assertContains "pod/pod-b unchanged"
assertContains "pod/pod-c unchanged"
assertContains "3 resource(s) applied. 0 created, 3 unchanged, 0 configured, 0 failed"
assertContains "4 resource(s) applied. 0 created, 4 unchanged, 0 configured, 0 failed"
wait 2

printResult
Expand Down Expand Up @@ -529,12 +527,11 @@ printResult
echo "[ResourceGroup] Testing initial apply dry-run"
echo "kpt live apply --dry-run e2e/live/testdata/rg-test-case-1a"
${BIN_DIR}/kpt live apply --dry-run e2e/live/testdata/rg-test-case-1a > $OUTPUT_DIR/status
assertContains "namespace/rg-test-namespace created (dry-run)"
assertContains "1 resource(s) applied. 1 created, 0 unchanged, 0 configured, 0 failed (dry-run)"
assertContains "pod/pod-a created (dry-run)"
assertContains "pod/pod-b created (dry-run)"
assertContains "pod/pod-c created (dry-run)"
assertContains "3 resource(s) applied. 3 created, 0 unchanged, 0 configured, 0 failed"
assertContains "namespace/rg-test-namespace created"
assertContains "pod/pod-a created"
assertContains "pod/pod-b created"
assertContains "pod/pod-c created"
assertContains "4 resource(s) applied. 4 created, 0 unchanged, 0 configured, 0 failed"
printResult

# Test: Basic kpt live apply
Expand All @@ -545,11 +542,10 @@ ${BIN_DIR}/kpt live apply e2e/live/testdata/rg-test-case-1a > $OUTPUT_DIR/status
# The ResourceGroup CRD is already installed.
assertNotContains "installing inventory ResourceGroup CRD"
assertContains "namespace/rg-test-namespace unchanged"
assertContains "1 resource(s) applied. 0 created, 1 unchanged, 0 configured, 0 failed"
assertContains "pod/pod-a created"
assertContains "pod/pod-b created"
assertContains "pod/pod-c created"
assertContains "3 resource(s) applied. 3 created, 0 unchanged, 0 configured, 0 failed"
assertContains "4 resource(s) applied. 3 created, 1 unchanged, 0 configured, 0 failed"
wait 2
# Validate resources in the cluster
# ConfigMap inventory with four inventory items.
Expand All @@ -565,11 +561,10 @@ ${BIN_DIR}/kpt live apply link-to-rg-test-case-1a > $OUTPUT_DIR/status
# The ResourceGroup CRD is already installed.
assertNotContains "installing inventory ResourceGroup CRD"
assertContains "namespace/rg-test-namespace unchanged"
assertContains "1 resource(s) applied. 0 created, 1 unchanged, 0 configured, 0 failed"
assertContains "pod/pod-a unchanged"
assertContains "pod/pod-b unchanged"
assertContains "pod/pod-c unchanged"
assertContains "3 resource(s) applied. 0 created, 3 unchanged, 0 configured, 0 failed"
assertContains "4 resource(s) applied. 0 created, 4 unchanged, 0 configured, 0 failed"
wait 2
# Validate resources in the cluster
# ConfigMap inventory with four inventory items.
Expand Down Expand Up @@ -602,14 +597,13 @@ echo "[ResourceGroup] Testing basic apply dry-run"
echo "kpt live apply --dry-run e2e/live/testdata/rg-test-case-1b"
cp -f e2e/live/testdata/rg-test-case-1a/Kptfile e2e/live/testdata/rg-test-case-1b
${BIN_DIR}/kpt live apply --dry-run e2e/live/testdata/rg-test-case-1b > $OUTPUT_DIR/status
assertContains "namespace/rg-test-namespace configured (dry-run)"
assertContains "1 resource(s) applied. 0 created, 0 unchanged, 1 configured, 0 failed (dry-run)"
assertContains "pod/pod-b configured (dry-run)"
assertContains "pod/pod-c configured (dry-run)"
assertContains "pod/pod-d created (dry-run)"
assertContains "3 resource(s) applied. 1 created, 0 unchanged, 2 configured, 0 failed (dry-run)"
assertContains "pod/pod-a pruned (dry-run)"
assertContains "1 resource(s) pruned, 0 skipped, 0 failed (dry-run)"
assertContains "namespace/rg-test-namespace configured"
assertContains "pod/pod-b configured"
assertContains "pod/pod-c configured"
assertContains "pod/pod-d created"
assertContains "4 resource(s) applied. 1 created, 0 unchanged, 3 configured, 0 failed"
assertContains "pod/pod-a pruned"
assertContains "1 resource(s) pruned, 0 skipped, 0 failed"
wait 2
# Validate resources in the cluster
# ConfigMap inventory with four inventory items.
Expand All @@ -626,11 +620,10 @@ echo "kpt live apply e2e/live/testdata/rg-test-case-1b"
${BIN_DIR}/kpt live apply e2e/live/testdata/rg-test-case-1b > $OUTPUT_DIR/status
assertNotContains "installing inventory ResourceGroup CRD" # CRD already installed
assertContains "namespace/rg-test-namespace unchanged"
assertContains "1 resource(s) applied. 0 created, 1 unchanged, 0 configured, 0 failed"
assertContains "pod/pod-b unchanged"
assertContains "pod/pod-c unchanged"
assertContains "pod/pod-d created"
assertContains "3 resource(s) applied. 1 created, 2 unchanged, 0 configured, 0 failed"
assertContains "4 resource(s) applied. 1 created, 3 unchanged, 0 configured, 0 failed"
assertContains "pod/pod-a pruned"
assertContains "1 resource(s) pruned, 0 skipped, 0 failed"
wait 2
Expand All @@ -647,12 +640,11 @@ printResult
echo "[ResourceGroup] Testing basic destroy dry-run"
echo "kpt live destroy --dry-run e2e/live/testdata/rg-test-case-1b"
${BIN_DIR}/kpt live destroy --dry-run e2e/live/testdata/rg-test-case-1b > $OUTPUT_DIR/status
assertContains "pod/pod-d deleted (dry-run)"
assertContains "pod/pod-c deleted (dry-run)"
assertContains "pod/pod-b deleted (dry-run)"
assertContains "3 resource(s) deleted, 0 skipped (dry-run)"
assertContains "namespace/rg-test-namespace deleted (dry-run)"
assertContains "1 resource(s) deleted, 0 skipped (dry-run)"
assertContains "pod/pod-d deleted"
assertContains "pod/pod-c deleted"
assertContains "pod/pod-b deleted"
assertContains "namespace/rg-test-namespace deleted"
assertContains "4 resource(s) deleted, 0 skipped"
# Validate resources NOT DESTROYED in the cluster
assertPodExists "pod-b" "rg-test-namespace"
assertPodExists "pod-c" "rg-test-namespace"
Expand All @@ -667,9 +659,8 @@ ${BIN_DIR}/kpt live destroy e2e/live/testdata/rg-test-case-1b > $OUTPUT_DIR/stat
assertContains "pod/pod-d deleted"
assertContains "pod/pod-c deleted"
assertContains "pod/pod-b deleted"
assertContains "3 resource(s) deleted, 0 skipped"
assertContains "namespace/rg-test-namespace deleted"
assertContains "1 resource(s) deleted, 0 skipped"
assertContains "4 resource(s) deleted, 0 skipped"
# Validate resources NOT in the cluster
assertPodNotExists "pod-b" "rg-test-namespace"
assertPodNotExists "pod-c" "rg-test-namespace"
Expand All @@ -684,7 +675,7 @@ cat e2e/live/testdata/stdin-test/pods.yaml | ${BIN_DIR}/kpt live apply - > $OUTP
assertContains "pod/pod-a created"
assertContains "pod/pod-b created"
assertContains "pod/pod-c created"
assertContains "3 resource(s) applied. 3 created, 0 unchanged, 0 configured, 0 failed"
assertContains "4 resource(s) applied. 3 created, 1 unchanged, 0 configured, 0 failed"
printResult
echo "cat e2e/live/testdata/stdin-test/pods.yaml | kpt live status -"
cat e2e/live/testdata/stdin-test/pods.yaml | ${BIN_DIR}/kpt live status - > $OUTPUT_DIR/status 2>&1
Expand All @@ -698,7 +689,7 @@ cat e2e/live/testdata/stdin-test/pods.yaml | ${BIN_DIR}/kpt live destroy - > $OU
assertContains "pod/pod-a deleted"
assertContains "pod/pod-b deleted"
assertContains "pod/pod-c deleted"
assertContains "3 resource(s) deleted, 0 skipped"
assertContains "4 resource(s) deleted, 0 skipped"
printResult

# Test: kpt live apply continue-on-error
Expand Down Expand Up @@ -829,11 +820,10 @@ echo "kpt live apply e2e/live/testdata/migrate-case-1b"
cp -f e2e/live/testdata/migrate-case-1a/Kptfile e2e/live/testdata/migrate-case-1b
${BIN_DIR}/kpt live apply e2e/live/testdata/migrate-case-1b > $OUTPUT_DIR/status
assertContains "namespace/test-rg-namespace unchanged"
assertContains "1 resource(s) applied. 0 created, 1 unchanged, 0 configured, 0 failed"
assertContains "pod/pod-b unchanged"
assertContains "pod/pod-c unchanged"
assertContains "pod/pod-d created"
assertContains "3 resource(s) applied. 1 created, 2 unchanged, 0 configured, 0 failed"
assertContains "4 resource(s) applied. 1 created, 3 unchanged, 0 configured, 0 failed"
assertContains "pod/pod-a pruned"
assertContains "1 resource(s) pruned, 0 skipped, 0 failed"
wait 2
Expand Down
10 changes: 7 additions & 3 deletions e2e/testdata/live-apply/apply-depends-on/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@
parallel: true

kptArgs:
- "--reconcile-timeout=1m"
- "--reconcile-timeout=2m"

stdOut: |
deployment.apps/first-nginx created
1 resource(s) applied. 1 created, 0 unchanged, 0 configured, 0 failed
deployment.apps/first-nginx reconcile pending
deployment.apps/first-nginx reconciled
deployment.apps/second-nginx created
1 resource(s) applied. 1 created, 0 unchanged, 0 configured, 0 failed
2 resource(s) applied. 2 created, 0 unchanged, 0 configured, 0 failed
deployment.apps/second-nginx reconcile pending
deployment.apps/second-nginx reconciled
2 resource(s) reconciled, 0 skipped, 0 failed to reconcile, 0 timed out
inventory:
- group: apps
Expand Down
8 changes: 6 additions & 2 deletions e2e/testdata/live-apply/crd-and-cr/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ kptArgs:

stdOut: |
customresourcedefinition.apiextensions.k8s.io/customs.kpt.dev created
1 resource(s) applied. 1 created, 0 unchanged, 0 configured, 0 failed
customresourcedefinition.apiextensions.k8s.io/customs.kpt.dev reconcile pending
customresourcedefinition.apiextensions.k8s.io/customs.kpt.dev reconciled
custom.kpt.dev/cr created
1 resource(s) applied. 1 created, 0 unchanged, 0 configured, 0 failed
2 resource(s) applied. 2 created, 0 unchanged, 0 configured, 0 failed
custom.kpt.dev/cr reconcile pending
custom.kpt.dev/cr reconciled
2 resource(s) reconciled, 0 skipped, 0 failed to reconcile, 0 timed out
inventory:
- group: apiextensions.k8s.io
kind: CustomResourceDefinition
Expand Down
4 changes: 2 additions & 2 deletions e2e/testdata/live-apply/dry-run-with-install-rg/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ kptArgs:
- "--dry-run"
- "--install-resource-group"
stdOut: |
deployment.apps/nginx-deployment created (dry-run)
1 resource(s) applied. 1 created, 0 unchanged, 0 configured, 0 failed (dry-run)
deployment.apps/nginx-deployment created
1 resource(s) applied. 1 created, 0 unchanged, 0 configured, 0 failed
stdErr: |
installing inventory ResourceGroup CRD.
exitCode: 0
18 changes: 13 additions & 5 deletions e2e/testdata/live-apply/json-output/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,24 @@
parallel: true
kptArgs:
- "--output=json"
- "--reconcile-timeout=1m"
- "--reconcile-timeout=2m"
stdOut: |
{"eventType":"resourceApplied","group":"","kind":"ConfigMap","name":"cm","namespace":"json-output","operation":"Created","timestamp":"<TIMESTAMP>","type":"apply"}
{"configuredCount":0,"count":1,"createdCount":1,"eventType":"completed","failedCount":0,"serverSideCount":0,"timestamp":"<TIMESTAMP>","type":"apply","unchangedCount":0}
{"eventType":"resourceReconciled","group":"","kind":"ConfigMap","name":"cm","namespace":"json-output","operation":"Pending","timestamp":"<TIMESTAMP>","type":"wait"}
{"eventType":"resourceReconciled","group":"","kind":"ConfigMap","name":"cm","namespace":"json-output","operation":"Reconciled","timestamp":"<TIMESTAMP>","type":"wait"}
{"eventType":"resourceApplied","group":"apps","kind":"Deployment","name":"nginx","namespace":"json-output","operation":"Created","timestamp":"<TIMESTAMP>","type":"apply"}
{"configuredCount":0,"count":1,"createdCount":1,"eventType":"completed","failedCount":0,"serverSideCount":0,"timestamp":"<TIMESTAMP>","type":"apply","unchangedCount":0}
{"configuredCount":0,"count":2,"createdCount":2,"eventType":"completed","failedCount":0,"serverSideCount":0,"timestamp":"<TIMESTAMP>","type":"apply","unchangedCount":0}
{"eventType":"resourceReconciled","group":"apps","kind":"Deployment","name":"nginx","namespace":"json-output","operation":"Pending","timestamp":"<TIMESTAMP>","type":"wait"}
{"eventType":"resourceReconciled","group":"apps","kind":"Deployment","name":"nginx","namespace":"json-output","operation":"Reconciled","timestamp":"<TIMESTAMP>","type":"wait"}
{"eventType":"resourcePruned","group":"apps","kind":"Deployment","name":"second-nginx","namespace":"json-output","operation":"Pruned","timestamp":"<TIMESTAMP>","type":"prune"}
{"eventType":"completed","pruned":1,"skipped":0,"timestamp":"<TIMESTAMP>","type":"prune"}
{"eventType":"resourceReconciled","group":"apps","kind":"Deployment","name":"second-nginx","namespace":"json-output","operation":"Pending","timestamp":"<TIMESTAMP>","type":"wait"}
{"eventType":"resourceReconciled","group":"apps","kind":"Deployment","name":"second-nginx","namespace":"json-output","operation":"Reconciled","timestamp":"<TIMESTAMP>","type":"wait"}
{"eventType":"resourcePruned","group":"apps","kind":"Deployment","name":"first-nginx","namespace":"json-output","operation":"Pruned","timestamp":"<TIMESTAMP>","type":"prune"}
{"eventType":"completed","pruned":1,"skipped":0,"timestamp":"<TIMESTAMP>","type":"prune"}
{"eventType":"completed","failed":0,"pruned":2,"skipped":0,"timestamp":"<TIMESTAMP>","type":"prune"}
{"eventType":"resourceReconciled","group":"apps","kind":"Deployment","name":"first-nginx","namespace":"json-output","operation":"Pending","timestamp":"<TIMESTAMP>","type":"wait"}
{"eventType":"resourceReconciled","group":"apps","kind":"Deployment","name":"first-nginx","namespace":"json-output","operation":"Reconciled","timestamp":"<TIMESTAMP>","type":"wait"}
{"eventType":"completed","failed":0,"reconciled":4,"skipped":0,"timeout":0,"timestamp":"<TIMESTAMP>","type":"wait"}
inventory:
- kind: ConfigMap
name: cm
Expand Down
11 changes: 9 additions & 2 deletions e2e/testdata/live-apply/prune-depends-on/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,17 @@ kptArgs:
stdOut: |
configmap/cm created
1 resource(s) applied. 1 created, 0 unchanged, 0 configured, 0 failed
configmap/cm reconcile pending
configmap/cm reconciled
deployment.apps/second-nginx pruned
1 resource(s) pruned, 0 skipped, 0 failed
deployment.apps/second-nginx reconcile pending
deployment.apps/second-nginx reconciled
deployment.apps/first-nginx pruned
1 resource(s) pruned, 0 skipped, 0 failed
2 resource(s) pruned, 0 skipped, 0 failed to prune
deployment.apps/first-nginx reconcile pending
deployment.apps/first-nginx reconciled
3 resource(s) reconciled, 0 skipped, 0 failed to reconcile, 0 timed out
inventory:
- kind: ConfigMap
name: cm
Expand Down
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,15 @@ require (
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca
golang.org/x/mod v0.5.1
gotest.tools v2.2.0+incompatible
k8s.io/api v0.22.3
k8s.io/api v0.22.3 // indirect
k8s.io/apiextensions-apiserver v0.22.2
k8s.io/apimachinery v0.22.3
k8s.io/cli-runtime v0.22.2
k8s.io/client-go v0.22.2
k8s.io/klog/v2 v2.10.0
k8s.io/kube-openapi v0.0.0-20211109043139-026bd182f079 // indirect
k8s.io/kubectl v0.22.2
k8s.io/utils v0.0.0-20210820185131-d34e5cb4466e
sigs.k8s.io/cli-utils v0.26.1-0.20220108032703-d7d63f4b6289
sigs.k8s.io/cli-utils v0.26.1-0.20220111001916-0c9b214db384
sigs.k8s.io/kustomize/api v0.8.11
sigs.k8s.io/kustomize/kyaml v0.13.1-0.20211203194734-cd2c6a1ad117
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1022,8 +1022,8 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/cli-utils v0.26.1-0.20220108032703-d7d63f4b6289 h1:4kv1Ge3sdzNPT96uRa5zU+vNczErzkoQYanbQmRgn60=
sigs.k8s.io/cli-utils v0.26.1-0.20220108032703-d7d63f4b6289/go.mod h1:8ll2fyx+bzjbwmwUnKBQU+2LDbMDsxy44DiDZ+drALg=
sigs.k8s.io/cli-utils v0.26.1-0.20220111001916-0c9b214db384 h1:wElBbmlm1HWOxmnn1YWf0hR6BLrFFkszKCBfOWDDYv0=
sigs.k8s.io/cli-utils v0.26.1-0.20220111001916-0c9b214db384/go.mod h1:8ll2fyx+bzjbwmwUnKBQU+2LDbMDsxy44DiDZ+drALg=
sigs.k8s.io/controller-runtime v0.10.1 h1:+eLHgY/VrJWnfg6iXUqhCUqNXgPH1NZeP9drNAAgWlg=
sigs.k8s.io/controller-runtime v0.10.1/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY=
sigs.k8s.io/kustomize/api v0.8.11 h1:LzQzlq6Z023b+mBtc6v72N2mSHYmN8x7ssgbf/hv0H8=
Expand Down
18 changes: 15 additions & 3 deletions internal/cmdapply/cmdapply.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@ import (
"github.com/GoogleContainerTools/kpt/internal/util/argutil"
"github.com/GoogleContainerTools/kpt/internal/util/strings"
"github.com/GoogleContainerTools/kpt/pkg/live"
"github.com/GoogleContainerTools/kpt/thirdparty/cli-utils/flagutils"
"github.com/GoogleContainerTools/kpt/thirdparty/cli-utils/printers"
"github.com/spf13/cobra"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/kubectl/pkg/cmd/util"
"sigs.k8s.io/cli-utils/cmd/flagutils"
"sigs.k8s.io/cli-utils/pkg/apply"
"sigs.k8s.io/cli-utils/pkg/common"
"sigs.k8s.io/cli-utils/pkg/inventory"
"sigs.k8s.io/cli-utils/pkg/printers"
)

// NewRunner returns a command runner
Expand Down Expand Up @@ -80,6 +80,8 @@ func NewRunner(ctx context.Context, factory util.Factory,
"If true, install the inventory ResourceGroup CRD before applying.")
c.Flags().BoolVar(&r.dryRun, "dry-run", false,
"dry-run apply for the resources in the package.")
c.Flags().BoolVar(&r.printStatusEvents, "status-events", false,
"Print status events (always enabled for table output)")
return r
}

Expand All @@ -105,6 +107,7 @@ type Runner struct {
pruneTimeout time.Duration
inventoryPolicyString string
dryRun bool
printStatusEvents bool

inventoryPolicy inventory.InventoryPolicy
prunePropPolicy v1.DeletionPropagation
Expand Down Expand Up @@ -226,8 +229,17 @@ func runApply(r *Runner, invInfo inventory.InventoryInfo, objs []*unstructured.U
InventoryPolicy: r.inventoryPolicy,
})

// Print the preview strategy unless the output format is json.
if dryRunStrategy.ClientOrServerDryRun() && r.output != printers.JSONPrinter {
if dryRunStrategy.ServerDryRun() {
fmt.Println("Dry-run strategy: server")
} else {
fmt.Println("Dry-run strategy: client")
}
}

// 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, dryRunStrategy)
return printer.Print(ch, dryRunStrategy, r.printStatusEvents)
}
Loading

0 comments on commit 5eb30e0

Please sign in to comment.